├── Binary Search └── binarySearch.js ├── Linked List └── linkedList.js ├── Longest Palindromic Substring └── longestPalindromicSubstring.js ├── Maximum Character in String └── maxCharinString.js ├── Merged Intervals └── mergedIntervals.js ├── README.md ├── Remove Duplicates from Sorted Array └── removeDuplicates.js ├── Remove Element └── removeElement.js ├── Roman to integer └── romanToInt.js ├── Running Sum 1d Array └── runningSum.js ├── Tree └── tree.js └── Two Sum └── twoSum.js /Binary Search/binarySearch.js: -------------------------------------------------------------------------------- 1 | //PSEUDO CODE 2 | 3 | // binary search works by spliting a sorted array into 2 4 | // compare the middle of the division to the search value 5 | // if its less than the middle, divide the left part of the division by 2 till you find the search value 6 | // if its more than the middle, divide the right part of the division by 2 till you find the search value 7 | 8 | const bSearch = function(arr, search) { 9 | let lowIndex = 0; 10 | let highIndex = arr.length - 1; 11 | 12 | while (lowIndex <= highIndex) { 13 | let middle = lowIndex + Math.floor((highIndex - lowIndex) / 2); 14 | 15 | if(arr[middle] === search) return middle; 16 | 17 | if(search < arr[middle]) { 18 | highIndex = middle - 1; 19 | }else{ 20 | lowIndex = middle + 1; 21 | } 22 | 23 | } 24 | 25 | return -1 26 | } 27 | -------------------------------------------------------------------------------- /Linked List/linkedList.js: -------------------------------------------------------------------------------- 1 | 2 | class ListNode { 3 | data: any; 4 | next: any; 5 | 6 | constructor(data){ 7 | this.data = data; 8 | this.next = null 9 | } 10 | } 11 | 12 | class LinkList { 13 | head: any; 14 | length: number; 15 | 16 | constructor(head: any = null) { 17 | this.head = head; 18 | this.length = 0; 19 | } 20 | 21 | unshift(data: any) { 22 | const newNode = new ListNode(data); 23 | newNode.next = this.head; 24 | this.head = newNode 25 | this.length++ 26 | } 27 | 28 | getFirst() { 29 | return this.head; 30 | } 31 | 32 | getLast() { 33 | let currentNode = this.head; 34 | 35 | while (currentNode && currentNode.next != null) { 36 | currentNode = currentNode.next 37 | 38 | } 39 | 40 | return currentNode; 41 | } 42 | 43 | clear() { 44 | this.head = null 45 | this.length = 0 46 | } 47 | 48 | shift() { 49 | if(this.head){ 50 | let currentNode = this.head 51 | 52 | this.head = currentNode.next 53 | this.length-- 54 | } 55 | } 56 | 57 | pop(){ 58 | if(this.length <= 1){ 59 | this.clear() 60 | return 61 | } 62 | const lastNode = this.getLast(); 63 | 64 | let currentNode = this.getFirst(); 65 | 66 | while(currentNode.next !== lastNode) { 67 | currentNode = currentNode.next 68 | } 69 | 70 | currentNode.next = null 71 | this.length-- 72 | } 73 | 74 | push(data) { 75 | const newNode = new ListNode(data); 76 | newNode.next = null; 77 | 78 | if(this.length < 1){ 79 | this.unshift(data) 80 | return 81 | } 82 | 83 | let last = this.getLast(); 84 | last.next = newNode; 85 | this.length++; 86 | } 87 | 88 | get(index){ 89 | if(index < 0 || (index + 1) > this.length) return null; 90 | let counter = 0; 91 | let currentNode = this.head; 92 | 93 | while(counter < index) { 94 | currentNode = currentNode.next 95 | counter++ 96 | } 97 | 98 | return currentNode 99 | } 100 | 101 | set(index, data){ 102 | const node = this.get(index); 103 | 104 | if(node){ 105 | node.data = data; 106 | return node 107 | } 108 | 109 | return null; 110 | } 111 | 112 | remove(index) { 113 | if(index < 0 || (index + 1) > this.length) return null; 114 | 115 | if(index < 1){ 116 | return this.shift() 117 | } 118 | 119 | if(index === this.length) { 120 | return this.pop() 121 | } 122 | 123 | let previousNode = this.get(index - 1) 124 | 125 | previousNode.next = previousNode.next.next 126 | this.length-- 127 | } 128 | 129 | insert(index, data) { 130 | if(index < 0 || index > this.length) return null; 131 | 132 | const newNode = new ListNode(data) 133 | 134 | if(index < 1){ 135 | return this.unshift(data) 136 | } 137 | 138 | if(index === this.length) { 139 | return this.push(data) 140 | } 141 | 142 | const currentIndexNode = this.get(index) 143 | const previousNode = this.get(index - 1) 144 | 145 | previousNode.next = newNode 146 | newNode.next = currentIndexNode 147 | this.length++ 148 | 149 | return 150 | 151 | } 152 | } -------------------------------------------------------------------------------- /Longest Palindromic Substring/longestPalindromicSubstring.js: -------------------------------------------------------------------------------- 1 | 2 | // PSEUDOCODE 3 | 4 | /** 5 | * 6 | * From the centre of the string, assign two pointers left and right. 7 | * continuosly check the left value is equal to the right using recursion to get the longest palindrome 8 | * in the case of an even word (eg ABAA), the center of the string will br the 2 characters in the middle 9 | * then compare the length of both the odd subscring and even substring 10 | * return the longest 11 | */ 12 | 13 | 14 | 15 | 16 | var longestPalindrome = function(s) { 17 | let longestStr = ''; 18 | 19 | for(let i = 0, len = s.length; i < len; i++) { 20 | let odd = expandFromCenter(s, i, i) // i and i is the same because the left and right pointer points to the same characters 21 | 22 | let even = expandFromCenter(s, i - 1, i) // i - 1 is left while i is right 23 | 24 | if(odd.length > longestStr.length) { 25 | longestStr = odd 26 | } 27 | 28 | if(even.length > longestStr.length) { 29 | longestStr = even 30 | } 31 | } 32 | 33 | return longestStr 34 | }; 35 | 36 | const expandFromCenter = function(string, left, right) { 37 | 38 | let i = 0; 39 | 40 | while(string[left - i] && string[left - i] === string[right + i]) { 41 | i++ 42 | } 43 | i-- 44 | 45 | return string.slice(left - i, right + i + 1) 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Maximum Character in String/maxCharinString.js: -------------------------------------------------------------------------------- 1 | //PSEUDO CODE 2 | 3 | // create a hash map to save the count pf each character in the string 4 | // keep track of the current max count in a variable 5 | // iterate over every character in the string 6 | // store the the occurence of each character in the hash map 7 | // compare if the occurence is the maax count and return if it is 8 | 9 | const maxCharStr = function (str) { 10 | let result = '' 11 | let currentMaxCount = 0 12 | let hMap = {}; 13 | 14 | for(let i = 0, len = str.length; i < len; i++) { 15 | const currentChar = str[i]; 16 | 17 | hMap[currentChar] = hMap[currentChar] + 1 || 1 18 | 19 | if(hMap[currentChar] > currentMaxCount) { 20 | result = currentChar 21 | currentMaxCount = hMap[currentChar] 22 | } 23 | } 24 | 25 | 26 | return result 27 | } 28 | -------------------------------------------------------------------------------- /Merged Intervals/mergedIntervals.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[][]} intervals 3 | * @return {number[][]} 4 | */ 5 | 6 | //TODO: 7 | // Sort the arrays onf intervals using the first indice of each array 8 | // Compare the second indice of the array to the first indice of the next array 9 | // If the next array first indice is less than the second indice of the first array 10 | // That means there is an overlapping interval 11 | // Merge the two arrays using the first indice of the first array and the second indice of the second array 12 | var merge = function(intervals) { 13 | // sort the array of intervals 14 | intervals.sort((a, b) => a[0] - b[0]); 15 | 16 | const resultInterval = [intervals[0]] 17 | 18 | for(let i = 0, len = intervals.length; i < len; i++) { 19 | 20 | let currentInterval = intervals[i]; 21 | let lastResultInterval = resultInterval[resultInterval.length - 1]; 22 | 23 | if(lastResultInterval[1] >= currentInterval[0]) { 24 | lastResultInterval[1] = Math.max(lastResultInterval[1], currentInterval[1]) 25 | }else{ 26 | resultInterval.push(currentInterval) 27 | } 28 | } 29 | 30 | 31 | return resultInterval 32 | 33 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Data Structure and Algo 2 | 3 | ## Practice repo for solving leetcode problems and also custom data structures -------------------------------------------------------------------------------- /Remove Duplicates from Sorted Array/removeDuplicates.js: -------------------------------------------------------------------------------- 1 | function removeDuplicates(nums) { 2 | const len = nums.length; 3 | if(len === 0) { 4 | return 0; 5 | } 6 | //start insertIndex at 1 as we're guaranteed to not have seen the value at 0 7 | let insertIndex = 1; 8 | //same goes for the loop 9 | for(let i = 1; i < len; i++) { 10 | //if the value at i is different from the one before it 11 | if(nums[i] !== nums[i - 1]) { 12 | //then modify the value of insertIndex *in place* to the value of i 13 | nums[insertIndex] = nums[i]; 14 | //now we can increment the insertIndex 15 | insertIndex++ 16 | } 17 | } 18 | 19 | console.log(nums) 20 | //we can use the insertIndex as the return since it is 21 | //equivalent to the num of unique values 22 | return insertIndex; 23 | }; 24 | -------------------------------------------------------------------------------- /Remove Element/removeElement.js: -------------------------------------------------------------------------------- 1 | var removeElement = function(nums, val) { 2 | let count = 0 3 | for (let i = 0; i < nums.length; i++) { 4 | if(nums[i] !== val) { 5 | nums[count] = nums[i] 6 | count++ 7 | } 8 | } 9 | 10 | console.log(nums) 11 | return count 12 | }; 13 | -------------------------------------------------------------------------------- /Roman to integer/romanToInt.js: -------------------------------------------------------------------------------- 1 | // PSEUDOCODE 2 | 3 | /** 4 | * 5 | * create a hash map with the value of each synol in the roman numeral 6 | * initiale the result number with 0 7 | * iterate the roman string 8 | * check the current string value in the hash if its less than the next character value 9 | * if its less than the next, subtract it from the next character. (case of IV) 10 | * 11 | */ 12 | 13 | var romanToInt = function (s) { 14 | const romanHash = { 15 | 'I': 1, 16 | 'V': 5, 17 | 'X': 10, 18 | 'L': 50, 19 | 'C': 100, 20 | 'D': 500, 21 | 'M': 1000, 22 | }; 23 | 24 | let result = 0; 25 | 26 | for(let i = 0, len = s.length; i < len; i++) { 27 | const currentVal = romanHash[s[i]]; 28 | const nextCharVal = romanHash[s[i + 1]]; 29 | 30 | if(currentVal < nextCharVal) { 31 | result += nextCharVal - currentVal; 32 | i++ 33 | }else{ 34 | result += currentVal; 35 | } 36 | } 37 | 38 | return result; 39 | } -------------------------------------------------------------------------------- /Running Sum 1d Array/runningSum.js: -------------------------------------------------------------------------------- 1 | var runningSum = function(nums) { 2 | 3 | // loop the array starting from index 1 4 | for(let i = 1, len = nums.length; i < len; i++){ 5 | 6 | // add the previous index value to the current indice 7 | nums[i] += nums[i - 1] 8 | } 9 | 10 | return nums 11 | }; -------------------------------------------------------------------------------- /Tree/tree.js: -------------------------------------------------------------------------------- 1 | class TreeNode { 2 | data: any 3 | left: any 4 | right: any 5 | 6 | constructor(data) { 7 | this.data = data; 8 | this.left = null; 9 | this.right = null; 10 | } 11 | } 12 | 13 | 14 | class BinarySearchTree { 15 | root: any; 16 | 17 | constructor() { 18 | this.root = null; 19 | } 20 | 21 | isEmpty() { 22 | return this.root === null; 23 | } 24 | 25 | add(data) { 26 | const newNode = new TreeNode(data); 27 | 28 | if(this.isEmpty()) { 29 | this.root = newNode; 30 | }else{ 31 | this.insertNodeRec(this.root, newNode); 32 | } 33 | } 34 | 35 | insertNodeRec(root, newNode) { 36 | if(newNode.data < root.data) { 37 | if(root.left === null) { 38 | root.left = newNode; 39 | }else{ 40 | this.insertNodeRec(root.left, newNode); 41 | } 42 | }else{ 43 | if(root.right === null) { 44 | root.right = newNode; 45 | }else{ 46 | this.insertNodeRec(root.right, newNode); 47 | } 48 | } 49 | } 50 | 51 | search(root, value){ 52 | if(!root) { 53 | return false 54 | } else {} 55 | 56 | if(root.data === value) { 57 | return true 58 | }else{ 59 | if(value < root.data) { 60 | return this.search(root.left, value); 61 | }else{ 62 | return this.search(root.right, value); 63 | } 64 | } 65 | } 66 | 67 | preOrder(root){ // depth-first search 68 | if(root){ 69 | console.log(root.data); 70 | this.preOrder(root.left); 71 | this.preOrder(root.right); 72 | } 73 | return null 74 | } 75 | 76 | inOrder(root){ // depth-first search 77 | if(root) { 78 | this.inOrder(root.left); 79 | console.log(root.data); 80 | this.inOrder(root.right); 81 | } 82 | } 83 | 84 | postOrder(root){ // depth-first search 85 | if(root) { 86 | this.postOrder(root.left); 87 | this.postOrder(root.right); 88 | console.log(root.data); 89 | } 90 | } 91 | 92 | levelOrder() { // breadth-first search 93 | const queue = []; 94 | 95 | queue.push(this.root); 96 | while(queue.length){ 97 | let currentVal = queue.shift(); 98 | console.log(currentVal.data); 99 | 100 | if(currentVal.left) { 101 | queue.push(currentVal.left); 102 | } 103 | 104 | if(currentVal.right) { 105 | queue.push(currentVal.right); 106 | } 107 | } 108 | } 109 | 110 | 111 | min(root) { 112 | if(!root.left) { 113 | return root.data 114 | }else{ 115 | return this.min(root.left) 116 | } 117 | } 118 | 119 | max(root) { 120 | if(!root.right) { 121 | return root.data 122 | }else{ 123 | return this.max(root.right) 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /Two Sum/twoSum.js: -------------------------------------------------------------------------------- 1 | //PSEUDOCODE 2 | 3 | // BRUTE FORCE: 4 | 5 | /** 6 | * brute force option would be to iterate over the nums array and 7 | * then a second loop to interate over the remaining numbers to check if it sums up to target 8 | * this solution works with a big O of O(n^2) but can be optimized for performance 9 | */ 10 | 11 | 12 | // IDEAL SOLUTION 13 | 14 | /** 15 | * Iterate over the numbers array, for each inetrated value, subtract the target from the iterated number 16 | * save the subtracted value as the key in a hashmap with the iterating indice being the value in the hashmap 17 | * if the subtracted value from the target is present in the hashmap, return the current iterating indice and the index of the subtracted value in the hashmap 18 | * 19 | */ 20 | 21 | 22 | var twoSum = function(nums, target) { 23 | 24 | const hashMap = {}; 25 | 26 | for(let i = 0, len = nums.length; i < len; i++) { 27 | let currentVal = nums[i] 28 | 29 | const toFind = target - currentVal; 30 | 31 | // look for toFind in the hashmap 32 | if(hashMap[toFind]) return [hashMap[toFind], i]; 33 | 34 | // its not, store the current value in the hashmap 35 | hashMap[currentVal] = i 36 | } 37 | return null; 38 | }; --------------------------------------------------------------------------------