├── .gitignore ├── 141-linked-list-cycle └── solution.js ├── 146-lru-cache └── solution.js ├── 19-remove-nth-node-from-end-of-list └── solution.js ├── 2-add-two-numbers └── solution.js ├── 20-valid-parentheses └── stack_solution.js ├── 200-number-of-islands ├── dfs.js └── union_find.js ├── 207-course-schedule ├── backtracking.js └── topological_sort.js ├── 21-merge-two-sorted-lists └── solution.js ├── 239-sliding-window-maximum └── dp.js ├── 242-valid-anagram ├── linear_solution_1.js ├── linear_solution_2.js └── sorting_solution.js ├── 252-meeting-rooms └── sorting.js ├── 253-meeting-rooms-II └── priority-queue-solution.js ├── 28-implement-strstr ├── brute-force.js └── kmp.js ├── 300-longest-increasing-subsequence ├── binary.js ├── build.js └── dp.js ├── 36-valid-sudoku ├── solution1.js ├── solution2.js └── solution3.js ├── 417-pacific-atlantic-water-flow └── bfs.js ├── 435-non-overlapping-intervals ├── solution1.js └── solution2.js ├── 55-jump-game ├── amortized.js ├── dynamic_programming.js ├── greedy.js └── recursive_backtracking.js ├── binary-heap ├── heap-sort.js └── priority-queue.js ├── custom ├── count_k_sorted_array.js └── square_root.js ├── interesting_problems ├── live_streams └── 133-clone-graph ├── morris-traversal ├── in-order.js ├── post-order.js └── pre-order.js ├── package.json └── sorting └── quicksort.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json -------------------------------------------------------------------------------- /141-linked-list-cycle/solution.js: -------------------------------------------------------------------------------- 1 | /* 2 | Floyd's cycle finding algorithm 3 | */ 4 | 5 | var hasCycle = function(head) { 6 | if(!head) return false 7 | let slow = head 8 | let fast = head.next 9 | while(fast && fast.next) { 10 | if(fast === slow) return true 11 | slow = slow.next 12 | fast = fast.next.next 13 | } 14 | return false 15 | }; -------------------------------------------------------------------------------- /146-lru-cache/solution.js: -------------------------------------------------------------------------------- 1 | class LRUCache { 2 | constructor(capacity){ 3 | // initialize hash map, linked list, save capacity, size 4 | this.map={} 5 | this.list=new DoublyLinkedList() 6 | this.capacity=capacity 7 | this.size=0 8 | } 9 | // -> value, -1 10 | get(key){ 11 | // if key doesn't exist, return -1 12 | if(!this.map[key]) return -1 13 | 14 | // if key exists, 15 | // move to front of linked list 16 | // return value 17 | const node = this.map[key] 18 | this.list.move2front(node) 19 | return node.value 20 | } 21 | put(key,value){ 22 | // key exists 23 | // => update value, move to front 24 | if(this.map[key]){ 25 | const node=this.map[key] 26 | node.value=value 27 | this.list.move2front(node) 28 | return 29 | } 30 | 31 | // key doesn't exist 32 | // if at capacity => remove last node from linked list and hash map 33 | // decrement size 34 | if(this.size===this.capacity){ 35 | const lastNode = this.list.removeLast() 36 | delete this.map[lastNode.key] 37 | this.size-=1 38 | } 39 | 40 | // add to linked list 41 | // save to hash map 42 | // increment size 43 | const newNode=new ListNode(key,value) 44 | this.list.add(newNode) 45 | this.map[key]=newNode 46 | this.size+=1 47 | 48 | } 49 | } 50 | 51 | class DoublyLinkedList{ 52 | // head - tail 53 | constructor(){ 54 | this.head=new ListNode() 55 | this.tail=new ListNode() 56 | this.connect(this.head,this.tail) 57 | } 58 | // head 3 59 | // \ / 60 | // 4 61 | add(node){ 62 | this.connect(node,this.head.next) 63 | this.connect(this.head,node) 64 | } 65 | // needs to return the node it deletes 66 | removeLast(){ 67 | const lastNode=this.tail.prev 68 | this.delete(lastNode) 69 | return lastNode 70 | } 71 | move2front(node){ 72 | this.delete(node) 73 | this.add(node) 74 | } 75 | connect(node1,node2){ 76 | node1.next=node2 77 | node2.prev=node1 78 | } 79 | delete(node){ 80 | this.connect(node.prev,node.next) 81 | } 82 | } 83 | 84 | class ListNode{ 85 | constructor(key,value){ 86 | this.key=key 87 | this.value=value 88 | this.next=null 89 | this.prev=null 90 | } 91 | } -------------------------------------------------------------------------------- /19-remove-nth-node-from-end-of-list/solution.js: -------------------------------------------------------------------------------- 1 | var removeNthFromEnd = function (head, n) { 2 | const prehead = new ListNode(0, head); 3 | let it1 = head; 4 | let it2 = prehead; 5 | while (n--) { 6 | it1 = it1.next; 7 | } 8 | while (it1) { 9 | it1 = it1.next; 10 | it2 = it2.next; 11 | } 12 | it2.next = it2.next.next; 13 | return prehead.next; 14 | }; 15 | -------------------------------------------------------------------------------- /2-add-two-numbers/solution.js: -------------------------------------------------------------------------------- 1 | const addTwoNumbers = (l1, l2) => { 2 | let carry = 0; 3 | let previousNode = new ListNode(); 4 | const headNode = previousNode; 5 | while (l1 || l2 || carry) { 6 | let val1 = 0; 7 | let val2 = 0; 8 | if (l1) { 9 | val1 = l1.val; 10 | l1 = l1.next; 11 | } 12 | if (l2) { 13 | val2 = l2.val; 14 | l2 = l2.next; 15 | } 16 | const sum = val1 + val2 + carry; 17 | carry = Math.floor(sum / 10); // sum > 9 ? 1 : 0 18 | const digit = sum % 10; 19 | const currentNode = new ListNode(digit); 20 | previousNode.next = currentNode; 21 | previousNode = currentNode; 22 | } 23 | return headNode.next; 24 | }; 25 | -------------------------------------------------------------------------------- /20-valid-parentheses/stack_solution.js: -------------------------------------------------------------------------------- 1 | var isValid = function (s) { 2 | const hashMap = { "(": ")", "{": "}", "[": "]" }; 3 | const stack = []; 4 | for (let ch of s) { 5 | if (hashMap[ch]) { 6 | // ch is an opening bracket 7 | stack.push(hashMap[ch]); 8 | } else if (stack.length > 0 && stack[stack.length - 1] === ch) { 9 | // ch is a closing bracket and top of stack matches 10 | stack.pop(); 11 | } else { 12 | // ch is a closing bracket and top of the stack doesn't match 13 | return false; 14 | } 15 | } 16 | return stack.length === 0; 17 | }; 18 | -------------------------------------------------------------------------------- /200-number-of-islands/dfs.js: -------------------------------------------------------------------------------- 1 | const directions = [ 2 | [-1, 0], 3 | [0, -1], 4 | [1, 0], 5 | [0, 1], 6 | ]; 7 | 8 | var numIslands = function (grid) { 9 | let count = 0; 10 | for (let i = 0; i < grid.length; i++) { 11 | for (let j = 0; j < grid[0].length; j++) { 12 | if (grid[i][j] !== "1") continue; 13 | count++; 14 | dfs(grid, i, j); 15 | } 16 | } 17 | return count; 18 | }; 19 | 20 | function dfs(grid, i, j) { 21 | grid[i][j] = "0"; 22 | for (let dir of directions) { 23 | let x = i + dir[0]; 24 | let y = j + dir[1]; 25 | if ( 26 | x >= 0 && 27 | y >= 0 && 28 | x < grid.length && 29 | y < grid[0].length && 30 | grid[x][y] === "1" 31 | ) { 32 | dfs(grid, x, y); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /200-number-of-islands/union_find.js: -------------------------------------------------------------------------------- 1 | const directions = [ 2 | [-1, 0], 3 | [0, -1], 4 | [1, 0], 5 | [0, 1], 6 | ]; 7 | 8 | const to1d = (x, y, cols) => x * cols + y; 9 | 10 | var numIslands = function (grid) { 11 | const uf = new UnionFind(grid); 12 | const rows = grid.length; 13 | const cols = grid[0].length; 14 | for (let i = 0; i < rows; i++) { 15 | for (let j = 0; j < cols; j++) { 16 | if (grid[i][j] === "0") continue; 17 | for (let dir of directions) { 18 | const x = i + dir[0]; 19 | const y = j + dir[1]; 20 | if (x < 0 || y < 0 || x >= rows || y >= cols || grid[x][y] === "0") 21 | continue; 22 | uf.union(to1d(i, j, cols), to1d(x, y, cols)); 23 | } 24 | } 25 | } 26 | return uf.count(); 27 | }; 28 | 29 | function UnionFind(grid) { 30 | const roots = {}; 31 | let count = 0; 32 | const rows = grid.length; 33 | const cols = grid[0].length; 34 | for (let i = 0; i < rows; i++) { 35 | for (let j = 0; j < cols; j++) { 36 | if (grid[i][j] === "0") continue; 37 | const id = to1d(i, j, cols); 38 | roots[id] = id; 39 | count++; 40 | } 41 | } 42 | this.union = (id1, id2) => { 43 | const find1 = this.find(id1); 44 | const find2 = this.find(id2); 45 | if (roots[find1] !== roots[find2]) { 46 | roots[find2] = find1; 47 | count--; 48 | } 49 | }; 50 | this.find = (id) => { 51 | while (roots[id] !== id) { 52 | roots[id] = roots[roots[id]]; 53 | id = roots[id]; 54 | } 55 | return id; 56 | }; 57 | this.count = () => count; 58 | } 59 | -------------------------------------------------------------------------------- /207-course-schedule/backtracking.js: -------------------------------------------------------------------------------- 1 | 2 | function buildGraph(prerequisites) { 3 | const graph = {} 4 | for(let prereq of prerequisites) { 5 | for(let course of prereq) { 6 | if(!graph[course]) { 7 | graph[course] = [] 8 | } 9 | } 10 | graph[prereq[1]].push(prereq[0]) 11 | } 12 | return graph 13 | } 14 | 15 | function hasCycle(graph, path, done, course) { 16 | if(path[course]) { 17 | return true 18 | } 19 | if(done[course]) { 20 | return false 21 | } 22 | path[course] = true 23 | done[course] = true 24 | for(let next of graph[course]) { 25 | if(hasCycle(graph, path, done, next)) { 26 | return true 27 | } 28 | } 29 | path[course] = false 30 | return false 31 | } 32 | 33 | var canFinish = function(numCourses, prerequisites) { 34 | const graph = buildGraph(prerequisites) 35 | const done = new Set() 36 | const path = new Set() 37 | for(let course of Object.keys(graph)) { 38 | if(!done.has(course) && hasCycle(graph, path, done, course)) { 39 | return false 40 | } 41 | } 42 | return true 43 | }; -------------------------------------------------------------------------------- /207-course-schedule/topological_sort.js: -------------------------------------------------------------------------------- 1 | var canFinish = function(numCourses, prerequisites) { 2 | const graph = {} 3 | for(let prereq of prerequisites) { 4 | for(let course of prereq) { 5 | if(!graph[course]) { 6 | graph[course] = { next: [], indeg: 0} 7 | } 8 | } 9 | graph[prereq[1]].next.push(prereq[0]) 10 | graph[prereq[0]].indeg += 1 11 | } 12 | 13 | let removedEdges = 0 14 | const queue = [] 15 | for(let course of Object.keys(graph)) { 16 | if(graph[course].indeg === 0) queue.push(course) 17 | } 18 | while(queue.length > 0) { 19 | const course = queue.shift() 20 | for(let nextCourse of graph[course].next) { 21 | graph[nextCourse].indeg -= 1 22 | removedEdges += 1 23 | if(graph[nextCourse].indeg === 0) queue.push(nextCourse) 24 | } 25 | } 26 | return removedEdges === prerequisites.length 27 | }; -------------------------------------------------------------------------------- /21-merge-two-sorted-lists/solution.js: -------------------------------------------------------------------------------- 1 | var mergeTwoLists = function(l1, l2) { 2 | const prehead = new ListNode() 3 | let prev = prehead 4 | while(l1 && l2) { 5 | if(l1.val < l2.val) { 6 | prev.next = l1 7 | l1 = l1.next 8 | } else { 9 | prev.next = l2 10 | l2 = l2.next 11 | } 12 | prev = prev.next 13 | } 14 | prev.next = l1 ? l1 : l2 15 | return prehead.next 16 | }; -------------------------------------------------------------------------------- /239-sliding-window-maximum/dp.js: -------------------------------------------------------------------------------- 1 | function print(arr) { 2 | let s = ""; 3 | console.log("" + arr); 4 | } 5 | 6 | var maxSlidingWindow = function (arr, w) { 7 | const max_left = new Array(arr.length); 8 | const max_right = new Array(arr.length); 9 | 10 | max_right[arr.length - 1] = arr[arr.length - 1]; 11 | 12 | for (let i = 0; i < arr.length; i++) { 13 | max_left[i] = i % w == 0 ? arr[i] : Math.max(max_left[i - 1], arr[i]); 14 | } 15 | for (let j = arr.length - 2; j >= 0; j--) { 16 | max_right[j] = j % w == 0 ? arr[j] : Math.max(max_right[j + 1], arr[j]); 17 | } 18 | 19 | // print(arr); 20 | // print(max_left); 21 | // print(max_right); 22 | let sliding_max = new Array(arr.length - w + 1); 23 | for (let i = 0; i + w <= arr.length; i++) { 24 | sliding_max[i] = Math.max(max_right[i], max_left[i + w - 1]); 25 | } 26 | 27 | return sliding_max; 28 | }; 29 | 30 | const arr = [1, 3, -1, -3, 5, 3, 6, 7]; 31 | const k = 3; 32 | console.log(maxSlidingWindow(arr, k)); 33 | -------------------------------------------------------------------------------- /242-valid-anagram/linear_solution_1.js: -------------------------------------------------------------------------------- 1 | var isAnagram = function (s, t) { 2 | if (s.length !== t.length) return false; 3 | const sCount = {}; 4 | const tCount = {}; 5 | const N = s.length; 6 | for (let i = 0; i < N; i++) { 7 | if (!sCount[s[i]]) sCount[s[i]] = 0; 8 | if (!tCount[t[i]]) tCount[t[i]] = 0; 9 | sCount[s[i]]++; 10 | tCount[t[i]]++; 11 | } 12 | for (let ch in sCount) { 13 | if (sCount[ch] !== tCount[ch]) return false; 14 | } 15 | return true; 16 | }; 17 | -------------------------------------------------------------------------------- /242-valid-anagram/linear_solution_2.js: -------------------------------------------------------------------------------- 1 | var isAnagram = function (s, t) { 2 | if(s.length !== t.length) return false 3 | const N = s.length 4 | const letterFrequency = {} 5 | for(let i=0;ia[0]-b[0]) 3 | for(let i=1;iintervals[i][0]) return false 5 | } 6 | return true 7 | }; -------------------------------------------------------------------------------- /253-meeting-rooms-II/priority-queue-solution.js: -------------------------------------------------------------------------------- 1 | require("google-closure-library"); 2 | 3 | goog.require("goog.structs.PriorityQueue"); 4 | 5 | // function PriorityQueue() { 6 | // const data = []; 7 | // this.isEmpty = () => data.length === 0; 8 | // this.peek = () => data[0]; 9 | // this.dequeue = () => { 10 | // const result = data.shift(); 11 | // data.sort((a, b) => a - b); 12 | // return result; 13 | // }; 14 | // this.enqueue = (value) => { 15 | // data.push(value); 16 | // data.sort((a, b) => a - b); 17 | // }; 18 | // this.getCount = () => data.length; 19 | // this.isEmpty = () => data.length === 0 20 | // this.print = () => console.log(data); 21 | // } 22 | 23 | var minMeetingRooms = function (intervals) { 24 | if (intervals.length <= 1) return intervals.length; 25 | intervals.sort((a, b) => a[0] - b[0]); 26 | let res = 0; 27 | let queue = new PriorityQueue(); 28 | for (interval of intervals) { 29 | // if the meeting is over, remove 30 | while (!queue.isEmpty() && queue.peek() <= interval[0]) queue.dequeue(); 31 | queue.enqueue(interval[1]); 32 | res = Math.max(res, queue.getCount()); 33 | } 34 | return res; 35 | }; 36 | 37 | // console.log( 38 | // minMeetingRooms([ 39 | // [0, 30], 40 | // [5, 20], 41 | // [10, 20], 42 | // [15, 20], 43 | // [20, 25], 44 | // [20, 30], 45 | // ]) 46 | // ); 47 | 48 | let queue = new goog.structs.PriorityQueue(); 49 | queue.enqueue(1,2) 50 | console.log(queue.dequeue()) 51 | -------------------------------------------------------------------------------- /28-implement-strstr /brute-force.js: -------------------------------------------------------------------------------- 1 | var strStr = function (string, substring) { 2 | // edge case: substring="" -> 0 3 | if (substring === "") return 0; 4 | for (let i = 0; i <= string.length - substring.length; i++) { 5 | // check if match 6 | let j = 0; 7 | for (; j < substring.length; j++) { 8 | if (substring[j] !== string[i + j]) break; 9 | } 10 | // if match return i 11 | if (j === substring.length) return i; 12 | } 13 | return -1; 14 | }; 15 | -------------------------------------------------------------------------------- /28-implement-strstr /kmp.js: -------------------------------------------------------------------------------- 1 | var strStr = function (string, substring) { 2 | // edge case: substring="" -> 0 3 | if (substring === "") return 0; 4 | const prefixTable = buildPrefixTable(substring); 5 | let i = 0; // location in string 6 | let j = 0; // location in substring 7 | while (i < string.length && j < substring.length) { 8 | if (string[i] === substring[j]) { 9 | // if characters match, we can move to check next characters 10 | i += 1; 11 | j += 1; 12 | } else if (j > 0) { 13 | // when characters do not match, and we have a repeating 14 | // suffix-prefix pair, we still need to check after the prefix 15 | j = prefixTable[j - 1]; 16 | } else { 17 | // if characters do no match, and no repetition, we can move on 18 | i += 1; 19 | } 20 | } 21 | return j === substring.length ? i - j : -1; 22 | }; 23 | 24 | function buildPrefixTable(s) { 25 | const table = [0]; 26 | let i = 1; // location in s 27 | let j = 0; // length of repeating prefix and suffix 28 | while (i < s.length) { 29 | // If characters match, then the repeating prefix-suffix pair 30 | // gets longer by 1 character 31 | if (s[i] === s[j]) { 32 | j += 1; 33 | table[i] = j; 34 | i += 1; 35 | } else if (j > 0) { 36 | // If the characters do no match, and we have repetition 37 | // in suffix and prefix, we still need to check 38 | // the character after the prefix 39 | j = table[j - 1]; 40 | } else { 41 | // When the characters don't match and no repeating 42 | // suffix-prefix pair, then we can move on 43 | table[i] = 0; 44 | i += 1; 45 | } 46 | } 47 | return table; 48 | } 49 | -------------------------------------------------------------------------------- /300-longest-increasing-subsequence/binary.js: -------------------------------------------------------------------------------- 1 | var lengthOfLIS = function (nums) { 2 | const sub = [nums[0]]; 3 | for (let i = 1; i < nums.length; i++) { 4 | let num = nums[i]; 5 | if (num > sub[sub.length - 1]) { 6 | sub.push(num); 7 | } else { 8 | let j = binary(sub, num); 9 | sub[j] = num; 10 | } 11 | } 12 | return sub.length; 13 | }; 14 | 15 | function binary(nums, n) { 16 | let left = 0; 17 | let right = nums.length - 1; 18 | while (left < right) { 19 | let i = Math.floor((left + right) / 2); 20 | if (nums[i] < n) { 21 | left = i + 1; 22 | } else { 23 | right = i; 24 | } 25 | } 26 | return left; 27 | } 28 | -------------------------------------------------------------------------------- /300-longest-increasing-subsequence/build.js: -------------------------------------------------------------------------------- 1 | var lengthOfLIS = function(nums) { 2 | const sub = [nums[0]] 3 | for(let i=1;isub[sub.length-1]){ 6 | sub.push(num) 7 | }else{ 8 | let j=0 9 | while(num>sub[j]) j++ 10 | sub[j]=num 11 | } 12 | } 13 | return sub.length 14 | }; -------------------------------------------------------------------------------- /300-longest-increasing-subsequence/dp.js: -------------------------------------------------------------------------------- 1 | var lengthOfLIS = function(nums) { 2 | const memo=[1] 3 | for(let i=1;i 37 | x >= 0 && y >= 0 && x < heights.length && y < heights[0].length; 38 | 39 | function bfs(heights, queue, memo) { 40 | while (queue.length > 0) { 41 | const [i, j] = queue.shift(); 42 | memo[i][j] = true; 43 | for (let dir of directions) { 44 | const x = i + dir[0]; 45 | const y = j + dir[1]; 46 | if ( 47 | isIn(heights, x, y) && 48 | memo[x][y] === undefined && 49 | heights[x][y] >= heights[i][j] 50 | ) { 51 | queue.push([x, y]); 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /435-non-overlapping-intervals/solution1.js: -------------------------------------------------------------------------------- 1 | // total intervals - # of intervals you can schedule 2 | 3 | var eraseOverlapIntervals = function (intervals) { 4 | if (intervals.length <= 1) return 0; 5 | intervals.sort((a, b) => a[1] - b[1]); 6 | let end = intervals[0][1]; 7 | let count = 1; 8 | for (let i = 1; i < intervals.length; i++) { 9 | if (intervals[i][0] >= end) { 10 | end = intervals[i][1]; 11 | count++; 12 | } 13 | } 14 | return intervals.length - count; 15 | }; 16 | -------------------------------------------------------------------------------- /435-non-overlapping-intervals/solution2.js: -------------------------------------------------------------------------------- 1 | 2 | var eraseOverlapIntervals = function(intervals) { 3 | if(intervals.length <= 1) return 0 4 | intervals.sort((a,b)=>a[1]-b[1]) 5 | let end = intervals[0][1] 6 | let count= 0 7 | for(let i=1;i= end) { 9 | end = intervals[i][1] 10 | } else { 11 | count++ 12 | } 13 | } 14 | return count 15 | }; -------------------------------------------------------------------------------- /55-jump-game/amortized.js: -------------------------------------------------------------------------------- 1 | var canJumpFromIndex = function(nums, index, memo) { 2 | if(memo[index] !== undefined) { 3 | return memo[index] 4 | } 5 | const maxIndex = Math.min(nums.length - 1, index + nums[index]) 6 | for(let i = index + 1; i <= maxIndex; i++) { 7 | if(canJumpFromIndex(nums, i, memo)) { 8 | memo[index] = true 9 | return true 10 | } 11 | } 12 | memo[index] = false 13 | return false 14 | }; 15 | 16 | var canJump = function(nums) { 17 | const memo = [] 18 | memo[nums.length - 1] = true 19 | return canJumpFromIndex(nums, 0, memo) 20 | }; -------------------------------------------------------------------------------- /55-jump-game/dynamic_programming.js: -------------------------------------------------------------------------------- 1 | var canJump = function(nums) { 2 | const memo = [] 3 | memo[nums.length - 1] = true 4 | for(let i = nums.length - 2; i >= 0; i--) { 5 | const maxIndex = Math.min(nums.length - 1, i + nums[i]) 6 | memo[i] = false 7 | for(let j = i + 1; j <= maxIndex; j++) { 8 | if(memo[j]) { 9 | memo[i] = true 10 | } 11 | } 12 | } 13 | return memo[0] 14 | }; -------------------------------------------------------------------------------- /55-jump-game/greedy.js: -------------------------------------------------------------------------------- 1 | var canJump = function(nums) { 2 | let goodIndex = nums.length - 1 3 | for(let i = nums.length - 2; i >= 0; i--) { 4 | if(goodIndex <= i + nums[i]) { 5 | goodIndex = i 6 | } 7 | } 8 | return goodIndex === 0 9 | }; -------------------------------------------------------------------------------- /55-jump-game/recursive_backtracking.js: -------------------------------------------------------------------------------- 1 | var canJump = function(nums, index = 0) { 2 | if(index === nums.length - 1) { 3 | return true 4 | } 5 | const maxSteps = nums[index] 6 | for(let step = 1; step <= maxSteps && index + step < nums.length; step++) { 7 | if(canJump(nums, index + step)) { 8 | return true 9 | } 10 | } 11 | return false 12 | }; -------------------------------------------------------------------------------- /binary-heap/heap-sort.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | [1,2,3,4,5] 4 | parent(i)=Math.floor(i/2) 5 | left(i)=2*i 6 | right(i)=2*i+1 7 | 8 | [0,1,2,3,4] 9 | parent(i)=Math.floor((i+1)/2)-1 10 | left(i)=2*(i+1)-1=2i+2-1=2i+1 11 | right(i)=2*(i+1)+1-1=2i+2=2(i+1) 12 | 13 | 14 | */ 15 | 16 | const parent = (i) => Math.floor((i + 1) / 2); 17 | const left = (i) => 2 * (i + 1) - 1; 18 | const right = (i) => 2 * (i + 1); 19 | 20 | const swap = (arr, i, j) => { 21 | const temp = arr[i]; 22 | arr[i] = arr[j]; 23 | arr[j] = temp; 24 | }; 25 | 26 | const maxHeapify = (arr, i, size = arr.length) => { 27 | const l = left(i); 28 | const r = right(i); 29 | let largest = i; 30 | if (l < size && arr[l] > arr[i]) largest = l; 31 | if (r < size && arr[r] > arr[largest]) largest = r; 32 | if (largest !== i) { 33 | swap(arr, i, largest); 34 | maxHeapify(arr, largest, size); 35 | } 36 | }; 37 | 38 | const buildMaxHeap = (arr, size = arr.length) => { 39 | for (let i = parent(size - 1); i >= 0; i--) { 40 | maxHeapify(arr, i, size); 41 | } 42 | }; 43 | 44 | const heapsort = (arr) => { 45 | buildMaxHeap(arr); 46 | let size = arr.length; 47 | for (let i = arr.length - 1; i > 0; i--) { 48 | swap(arr, 0, i); 49 | size--; 50 | maxHeapify(arr, 0, size); 51 | } 52 | }; 53 | 54 | const arr = [2, 1, 5, 3, 8, 7, 2, 3, 6]; 55 | console.log(arr); 56 | heapsort(arr); 57 | console.log(arr); 58 | -------------------------------------------------------------------------------- /binary-heap/priority-queue.js: -------------------------------------------------------------------------------- 1 | class PriorityQueue { 2 | constructor(comp) { 3 | this.data = []; 4 | this.comp = comp; 5 | } 6 | empty() { 7 | return this.data.length === 0; 8 | } 9 | top() { 10 | if (this.empty()) throw new Error("Heap is empty"); 11 | return this.data[0]; 12 | } 13 | size() { 14 | return this.data.length; 15 | } 16 | pop() { 17 | if (this.empty()) throw new Error("Heap is empty"); 18 | this.data[0] = this.data[this.size() - 1]; 19 | this.data.pop(); 20 | this._heapify(0); 21 | } 22 | push(val) { 23 | this.data.push(val); 24 | let i = this.size() - 1; 25 | while (i > 0 && this.comp(this.data[this._parent(i)], this.data[i]) > 0) { 26 | this._swap(i, this._parent(i)); 27 | i = this._parent(i); 28 | } 29 | } 30 | print() { 31 | console.log(this.data); 32 | } 33 | _parent(i) { 34 | return Math.floor((i + 1) / 2) - 1; 35 | } 36 | _left(i) { 37 | return 2 * (i + 1) - 1; 38 | } 39 | _right(i) { 40 | return 2 * (i + 1); 41 | } 42 | _heapify(i) { 43 | const l = this._left(i); 44 | const r = this._right(i); 45 | let largest = i; 46 | if (l < this.size() && this.comp(this.data[i], this.data[l]) > 0) 47 | largest = l; 48 | if (r < this.size() && this.comp(this.data[largest], this.data[r]) > 0) 49 | largest = r; 50 | if (largest !== i) { 51 | this._swap(i, largest); 52 | this._heapify(largest); 53 | } 54 | } 55 | _swap(i, j) { 56 | const temp = this.data[i]; 57 | this.data[i] = this.data[j]; 58 | this.data[j] = temp; 59 | } 60 | } 61 | 62 | const pq = new PriorityQueue((a, b) => a[1] - b[1]); 63 | pq.print(); 64 | const arr = [2, 1, 5, 3, 8, 7, 2, 3, 6]; 65 | for (let i = 0; i < arr.length; i++) { 66 | console.log("add: ", arr[i]); 67 | pq.push([i, arr[i]]); 68 | pq.print(); 69 | } 70 | const sorted = []; 71 | while (!pq.empty()) { 72 | console.log("remove"); 73 | sorted.push(pq.top()); 74 | pq.pop(); 75 | pq.print(); 76 | } 77 | console.log(sorted); 78 | -------------------------------------------------------------------------------- /custom/count_k_sorted_array.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Find total accurence of element k in a sorted array 4 | 5 | binary search for lower and upper bounds seperately 6 | 0 1 2 3 4 5 6 7 | [1,2,3,3,3,4,5] 8 | lo=0 9 | hi=6 10 | mid = 3 11 | 12 | Lower bound: 13 | mid=Math.floor((upper+lower)/2) 14 | Case 1: arr[mid]=k 17 | hi = mid 18 | 19 | Upper bound: 20 | mid=Math.ceil((upper+lower)/2) 21 | Case 1: arr[mid]<=k 22 | lo =mid 23 | Case 2: arr[mid] >k 24 | hi=mid-1 25 | 26 | 27 | 28 | The issue is with the case when arr[mid]===k 29 | The tricky part is to avoid infinite loop 30 | Case 3: arr[mid]===k 31 | subcase: arr[lo]===arr[hi] break 32 | 33 | [1,2,3] 34 | k=9 35 | lo=2 36 | hi=2 37 | mid=2 38 | 39 | 40 | */ 41 | 42 | function findBound(arr, k, boundType) { 43 | let lo = 0; 44 | let hi = arr.length - 1; 45 | while (lo < hi) { 46 | let mid = (hi + lo) / 2; 47 | mid = boundType === "LOWER" ? Math.floor(mid) : Math.ceil(mid); 48 | if (arr[mid] < k) { 49 | lo = mid + 1; 50 | } else if (arr[mid] > k) { 51 | hi = mid - 1; 52 | } else if (boundType === "LOWER") { 53 | hi = mid; 54 | } else { 55 | lo = mid; 56 | } 57 | } 58 | return hi; 59 | } 60 | 61 | function countK(arr, k) { 62 | if (k < arr[0] || k >= arr[arr.length - 1]) return 0; 63 | let lo = findBound(arr, k, "LOWER"); 64 | let hi = findBound(arr, k, "UPPER"); 65 | 66 | return hi - lo + 1; 67 | } 68 | 69 | console.log(countK([1, 2, 3, 3, 3, 4, 5], 3)); 70 | console.log(countK([1, 2, 3, 3, 3, 4, 5], 2)); 71 | console.log(countK([1, 2, 3, 3, 3, 4, 6], 5)); 72 | console.log(countK([1, 2, 3, 3, 3, 4, 6], 0)); 73 | console.log(countK([1, 2, 3, 3, 3, 4, 6], 9)); 74 | -------------------------------------------------------------------------------- /custom/square_root.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | |y-x*x| < error 4 | 5 | 6 | 0.25,0.001 7 | lo=0.25 8 | hi=0.625 9 | mid=1.25/2=0.625 10 | mid2 =0.36 11 | Math.abs(y-mid2)=0.11 12 | 13 | edge cases: 0,1 14 | */ 15 | 16 | const sqrt=(y,error)=>{ 17 | if(y < 0) return NaN 18 | let lo=y 19 | let hi=1 20 | if(y>=1){ 21 | lo=1 22 | hi=y 23 | } 24 | while(lo",Math.sqrt(-1), sqrt(-1,0.001)) 38 | console.log("0, 0.001 ->",Math.sqrt(0), sqrt(0,0.001)) 39 | console.log("1, 0.1 ->",Math.sqrt(1), sqrt(1,0.1)); 40 | console.log("0.25,0.001 ->",Math.sqrt(0.25), sqrt(0.25,0.001)); 41 | console.log("20,1 ->",Math.sqrt(20), sqrt(20,1)); 42 | console.log("100,1 ->",Math.sqrt(100), sqrt(100,1)); -------------------------------------------------------------------------------- /interesting_problems: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Write an algorithm to compute the square root of a given non-negative number. Since the true square root of a number may have infinitely many digits, we bound the accuracy of the square root by a second parameter, called the error. 4 | 5 | For a given number target and error e, find a square root x that satisfies the following: 6 | math.abs(x**2 - target) < e 7 | 8 | e.g. SquareRoot(target=100.0, error=2.0) = 9 | 9.9**2 = 98.01 10 | 11 | */ 12 | 13 | 14 | 15 | validate binary search tree 16 | 17 | 50 18 | 20 200 19 | 5 30 60 20 | 35 190 21 | 70 22 | 23 | validate(root) 24 | 25 | Node: 26 | int value 27 | Node* left 28 | Node* right 29 | 30 | all values unique 31 | 32 | 33 | -------------------------------------------------------------------------------- /live_streams/133-clone-graph: -------------------------------------------------------------------------------- 1 | var cloneGraph = function (node) { 2 | if (!node) return node; 3 | const copy = new Map(); 4 | let queue = [node]; 5 | let visited = new Set(); 6 | while (queue.length > 0) { 7 | const n = queue.shift(); 8 | visited.add(n); 9 | copy.set(n, new Node(n.val, n.neighbors)); 10 | for (let i = 0; i < n.neighbors.length; i++) { 11 | if (!visited.has(n.neighbors[i])) { 12 | queue.push(n.neighbors[i]); 13 | } 14 | } 15 | } 16 | visited = new Set(); 17 | queue = [copy.get(node)]; 18 | while (queue.length > 0) { 19 | const n = queue.shift(); 20 | if (visited.has(n)) continue; 21 | visited.add(n); 22 | n.neighbors = n.neighbors.map((neighbor) => copy.get(neighbor)); 23 | for (let i = 0; i < n.neighbors.length; i++) { 24 | if (!visited.has(n.neighbors[i])) { 25 | queue.push(n.neighbors[i]); 26 | } 27 | } 28 | } 29 | return copy.get(node); 30 | }; 31 | -------------------------------------------------------------------------------- /morris-traversal/in-order.js: -------------------------------------------------------------------------------- 1 | var inorderTraversal = function (root) { 2 | let node = root; 3 | const result = []; 4 | while (node) { 5 | if (!node.left) { 6 | result.push(node.val); 7 | node = node.right; 8 | } else { 9 | const pred = findPredecessor(node); 10 | if (pred.right === node) { 11 | pred.right = null; 12 | result.push(node.val); 13 | node = node.right; 14 | } else { 15 | pred.right = node; 16 | node = node.left; 17 | } 18 | } 19 | } 20 | return result; 21 | }; 22 | function findPredecessor(root) { 23 | let node = root.left; 24 | while (node.right && node.right !== root) { 25 | node = node.right; 26 | } 27 | return node; 28 | } 29 | -------------------------------------------------------------------------------- /morris-traversal/post-order.js: -------------------------------------------------------------------------------- 1 | function findPredecessor(root) { 2 | if (!root.left) return root; 3 | let cur = root.left; 4 | while (cur.right && cur.right !== root) cur = cur.right; 5 | return cur; 6 | } 7 | 8 | //This is Post Order :children before node( L ,R , N) 9 | var postorderTraversal = function (root) { 10 | // Making our tree left subtree of a dummy Node 11 | const dummyRoot = new TreeNode(0, root); 12 | //Think of P as the current node 13 | let p = dummyRoot; 14 | let first; 15 | let middle; 16 | let last; 17 | const result = []; 18 | while (p !== null) { 19 | if (p.left === null) { 20 | p = p.right; 21 | } else { 22 | // p has a left child => it also has a predeccessor 23 | // make p as right child predeccessor of p 24 | 25 | const pred = findPredecessor(p); 26 | if (pred.right === null) { 27 | // predeccessor found for first time 28 | // modify the tree 29 | pred.right = p; 30 | p = p.left; 31 | } else { 32 | // predeccessor found second time 33 | // reverse the right references in chain from pred to p 34 | first = p; 35 | middle = p.left; 36 | while (middle != p) { 37 | last = middle.right; 38 | middle.right = first; 39 | first = middle; 40 | middle = last; 41 | } 42 | // visit the nodes from pred to p 43 | // again reverse the right references from pred to p 44 | first = p; 45 | middle = pred; 46 | while (middle != p) { 47 | result.push(middle.val); 48 | last = middle.right; 49 | middle.right = first; 50 | first = middle; 51 | middle = last; 52 | } 53 | // remove the pred to node reference to restore the tree structure 54 | pred.right = null; 55 | p = p.right; 56 | } 57 | } 58 | } 59 | return result; 60 | }; 61 | -------------------------------------------------------------------------------- /morris-traversal/pre-order.js: -------------------------------------------------------------------------------- 1 | var preorderTraversal = function (root) { 2 | let cur = root; 3 | const result = []; 4 | while (cur) { 5 | if (!cur.left) { 6 | result.push(cur.val); 7 | cur = cur.right; 8 | } else { 9 | predecessor = findPredecessor(cur); 10 | if (!predecessor.right) { 11 | result.push(cur.val); 12 | predecessor.right = cur; 13 | cur = cur.left; 14 | } else { 15 | predecessor.rights = null; 16 | cur = cur.right; 17 | } 18 | } 19 | } 20 | return result; 21 | }; 22 | 23 | function findPredecessor(root) { 24 | if (!root.left) return root; 25 | let cur = root.left; 26 | while (cur.right && cur.right !== root) cur = cur.right; 27 | return cur; 28 | } 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "google-closure-library": "^20210601.0.0" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /sorting/quicksort.js: -------------------------------------------------------------------------------- 1 | function quicksort(arr, start = 0, end = arr.length - 1) { 2 | if (start >= end) return; 3 | const pivot = arr[end]; 4 | let i = start - 1; 5 | for (let j = start; j < end; j++) { 6 | if (arr[j] < pivot) { 7 | swap(arr, ++i, j); 8 | } 9 | } 10 | swap(arr, ++i, end); 11 | quicksort(arr, start, i - 1); 12 | quicksort(arr, i + 1, end); 13 | } 14 | 15 | function swap(arr, lo, hi) { 16 | const temp = arr[lo]; 17 | arr[lo] = arr[hi]; 18 | arr[hi] = temp; 19 | } 20 | 21 | let arr = [2, 4, 3, 5]; 22 | console.log(`${arr} -> `); 23 | quicksort(arr); 24 | console.log(` ${arr}`); 25 | 26 | arr = [2, 5, 8, 9, 3, 4]; 27 | console.log(`${arr} ->`); 28 | quicksort(arr); 29 | console.log(` ${arr}`); 30 | 31 | arr = [1, 1, 4, 88, 3, 4, 0, 2, 2]; 32 | console.log(`${arr} -> `); 33 | quicksort(arr); 34 | console.log(` ${arr}`); 35 | --------------------------------------------------------------------------------