├── .gitignore ├── 000__easy__temp.js ├── 011__medium__container-with-most-water.js ├── 013__easy__roman-to-integer.js ├── 024__medium__swap-nodes-in-pairs.js ├── 094__medium__binary-tree-inorder-traversal.js ├── 101__easy__symmetric-tree.js ├── 102__medium__binary-tree-level-order-traversal.js ├── 104__easy__maximum-depth-of-binary-tree.js ├── 105__medium__construct-binary-tree-from-preorder-and-inorder-traversal.js ├── 106__medium__construct-binary-tree-from-inorder-and-postorder-traversal.js ├── 112__easy__path-sum.js ├── 116__medium__populating-next-right-pointers-in-each-node.js ├── 117__medium__populating-next-right-pointers-in-each-node-ii.js ├── 119__easy__pascals_triangle_ii.js ├── 121__easy__best-time-to-buy-and-sell-stock.js ├── 122__easy__best-time-to-buy-and-sell-stock-ii.js ├── 134__medium__binary-tree-inorder-traversal.js ├── 136__easy__single_number.js ├── 144__medium__binary-tree-preorder-traversal.js ├── 145__hard__binary-tree-postorder-traversal.js ├── 151__medium__reverse_words_in_a_string.js ├── 169__easy__majority-element.js ├── 170__easy__two-sum-iii-data-structure-design.js ├── 189__easy__rotate-array.js ├── 1__easy__two-sum.js ├── 202__easy__happy-number.js ├── 205__easy__isomorphic-strings.js ├── 206__easy__reverse-linked-list.js ├── 217__easy__contains-duplicate.js ├── 219__easy__contains-duplicate-ii.js ├── 237__easy__delete-node-in-a-linked-list.js ├── 238__medium__product-of-array-except-self.js ├── 249__medium__group-shifted-strings.js ├── 250__medium__count-univalue-subtrees.js ├── 26__easy__remove-duplicates-from-sorted-array.js ├── 283__easy__move-zeroes.js ├── 288__medium__unique-word-abbreviation.js ├── 344__easy__reverse-string.js ├── 347__medium__top-k-frequent-elements.js ├── 349__easy__intersection-of-two-arrays.js ├── 350__easy__intersection-of-two-arrays-ii.js ├── 359__easy__logger-rate-limiter.js ├── 36__medium__valid-sudoku.js ├── 380__medium__insert-delete-getrandom-o1.js ├── 387__easy__first-unique-character-in-a-string.js ├── 3__medium__longest-substring-without-repeating-characters.js ├── 412__easy__fizz_buzz.js ├── 454__medium__4sum-ii.js ├── 461__easy__hamming-distance.js ├── 489__hard__robot-room-cleaner.js ├── 49__medium__group-anagrams.js ├── 557__easy__reverse-words-in-a-string-iii.js ├── 561__easy__array-partition-i.js ├── 599__easy__minimum-index-sum-of-two-lists.js ├── 617__easy__merge-two-binary-trees.js ├── 652__medium__find-duplicate-subtrees.js ├── 705__easy__design-hashset.js ├── 706__easy__design-hashmap.js ├── 709__easy__to-lower-case.js ├── 760__easy__find-anagram-mappings.js ├── 771__easy__jewels-and-stones.js ├── 852__easy__peak-index-in-a-mountain-array.js ├── 922__easy__sort-array-by-parity-ii.js ├── Algorithm Implementation └── QuickSort.js ├── Others └── debounce.js ├── Python3 ├── 000__easy__temp.py └── 680__easy__valid-palindrome-ii.py ├── README.md └── Typescript ├── 121__easy_Best Time to Buy and Sell Stock.ts ├── 125__easy_Valid Palindrome.ts ├── 169__easy_Majority Element.ts ├── 189__Medium_Rotate Array.ts ├── 1__easy_Two Sum.ts ├── 205__easy_Isomorphic Strings.ts ├── 242__easy_Valid Anagram.ts ├── 26__easy_Remove Duplicates from Sorted Array.ts ├── 27__easy_Remove Element.ts ├── 383__easy_Ransom Note.ts ├── 392__easy_Is Subsequence.ts ├── 80__medium_Remove Duplicates from Sorted Array II.ts └── 88__easy_Merge Sorted Array.ts /.gitignore: -------------------------------------------------------------------------------- 1 | # vscode 2 | *.vscode/ 3 | .vscode 4 | .vscode/* 5 | !.vscode/settings.json 6 | !.vscode/tasks.json 7 | !.vscode/launch.json 8 | !.vscode/extensions.json -------------------------------------------------------------------------------- /000__easy__temp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param 3 | * @return 4 | */ 5 | 6 | /** 7 | * 8 | * O(n) time 9 | * O(1) space 10 | * 11 | * 10m 12 | */ 13 | -------------------------------------------------------------------------------- /011__medium__container-with-most-water.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | LINK: https://leetcode.com/problems/container-with-most-water/ 4 | 5 | Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water. 6 | 7 | Note: You may not slant the container and n is at least 2. 8 | 9 | 10 | The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49. 11 | 12 | 13 | Example: 14 | 15 | Input: [1,8,6,2,5,4,8,3,7] 16 | Output: 49 17 | 18 | */ 19 | 20 | /** 21 | * 22 | * O(n) time 23 | * O(1) space 24 | * 25 | */ 26 | var maxArea = function(height) { 27 | let left = 0; 28 | let right = height.length-1; 29 | let max = 0; 30 | 31 | while (left < right) { 32 | max = Math.max(max, Math.min(height[left], height[right]) * (right - left)); 33 | if (height[left] < height[right]) { 34 | left++; 35 | } else { 36 | right--; 37 | } 38 | } 39 | return max; 40 | }; -------------------------------------------------------------------------------- /013__easy__roman-to-integer.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M. 4 | 5 | Symbol Value 6 | I 1 7 | V 5 8 | X 10 9 | L 50 10 | C 100 11 | D 500 12 | M 1000 13 | For example, two is written as II in Roman numeral, just two one's added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II. 14 | 15 | Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used: 16 | 17 | I can be placed before V (5) and X (10) to make 4 and 9. 18 | X can be placed before L (50) and C (100) to make 40 and 90. 19 | C can be placed before D (500) and M (1000) to make 400 and 900. 20 | Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999. 21 | 22 | Example 1: 23 | 24 | Input: "III" 25 | Output: 3 26 | Example 2: 27 | 28 | Input: "IV" 29 | Output: 4 30 | Example 3: 31 | 32 | Input: "IX" 33 | Output: 9 34 | Example 4: 35 | 36 | Input: "LVIII" 37 | Output: 58 38 | Explanation: L = 50, V= 5, III = 3. 39 | Example 5: 40 | 41 | Input: "MCMXCIV" 42 | Output: 1994 43 | Explanation: M = 1000, CM = 900, XC = 90 and IV = 4. 44 | 45 | */ 46 | 47 | /** 48 | * 49 | * O(n) time 50 | * O(1) space 51 | * 52 | * 15m 53 | */ 54 | /** 55 | * @param {string} s 56 | * @return {number} 57 | */ 58 | var romanToInt = function(s) { 59 | if (!s) return 0; 60 | const map = { 61 | 'I': 1, 62 | 'V': 5, 63 | 'X': 10, 64 | 'L': 50, 65 | 'C': 100, 66 | 'D': 500, 67 | 'M': 1000 68 | } 69 | let sum = map[s[s.length-1]]; 70 | for (let i = s.length-2; i >= 0; i--) { 71 | if (map[s[i]] >= map[s[i+1]]) { 72 | sum += map[s[i]]; 73 | } else { 74 | sum -= map[s[i]]; 75 | } 76 | } 77 | return sum; 78 | }; -------------------------------------------------------------------------------- /024__medium__swap-nodes-in-pairs.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given a linked list, swap every two adjacent nodes and return its head. 4 | You may not modify the values in the list's nodes, only nodes itself may be changed. 5 | 6 | Example: 7 | Given 1->2->3->4, you should return the list as 2->1->4->3. 8 | 9 | */ 10 | 11 | /** 12 | * 13 | * O(n) time 14 | * O(1) space 15 | * 16 | * 25m 17 | */ 18 | var swapPairs = function (head) { 19 | if (!head || !head.next) return head; 20 | 21 | let hd = new ListNode(); 22 | hd = head.next; 23 | 24 | while (head && head.next) { 25 | let h1 = head; 26 | let h2 = head.next; 27 | let h3 = head.next.next; 28 | head.next.next = head; 29 | if (h3 && h3.next) { 30 | head.next = h3.next; 31 | } else { 32 | head.next = h3; 33 | } 34 | head = h3; 35 | } 36 | return hd; 37 | }; -------------------------------------------------------------------------------- /094__medium__binary-tree-inorder-traversal.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given a binary tree, return the inorder traversal of its nodes' values. 4 | 5 | Example: 6 | 7 | Input: [1,null,2,3] 8 | 1 9 | \ 10 | 2 11 | / 12 | 3 13 | 14 | Output: [1,3,2] 15 | Follow up: Recursive solution is trivial, could you do it iteratively? 16 | 17 | */ 18 | /** 19 | * 20 | * O(n) time 21 | * O(n) space 22 | * 23 | * 10m 24 | */ 25 | var inorderTraversal = function(root) { 26 | if (!root || root.length == 0) return []; 27 | 28 | let res = []; 29 | let stack = []; 30 | let curr = root; 31 | 32 | while (curr || stack.length > 0) { 33 | while (curr) { 34 | stack.push(curr); 35 | curr = curr.left; 36 | } 37 | curr = stack.pop(); 38 | res.push(curr.val); 39 | curr = curr.right; 40 | } 41 | return res; 42 | }; -------------------------------------------------------------------------------- /101__easy__symmetric-tree.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). 4 | 5 | For example, this binary tree [1,2,2,3,4,4,3] is symmetric: 6 | 7 | 1 8 | / \ 9 | 2 2 10 | / \ / \ 11 | 3 4 4 3 12 | But the following [1,2,2,null,3,null,3] is not: 13 | 1 14 | / \ 15 | 2 2 16 | \ \ 17 | 3 3 18 | 19 | Note: 20 | Bonus points if you could solve it both recursively and iteratively. 21 | 22 | */ 23 | 24 | /** 25 | * recursively 26 | * 27 | * O(n) time (traverse the entire input tree once) 28 | * O(n) space (worst) The number of recursive calls is bound by the height of the tree. 29 | * In the worst case, the tree is linear and the height is in O(n). 30 | * 15m 31 | */ 32 | var isSymmetric = function(root) { 33 | if (!root) return true; 34 | const isMirr = (a, b) => { 35 | if (!a && !b) return true; 36 | if (!a || !b || a.val !== b.val) return false; 37 | return isMirr(a.left, b.right) && isMirr(a.right, b.left); 38 | }; 39 | return isMirr(root.left, root.right); 40 | }; 41 | 42 | /** 43 | * Iterative 44 | * 45 | * O(n) time (traverse the entire input tree once) 46 | * O(n) space (worst) queue 47 | * In the worst case, we have to insert O(n) nodes in the queue 48 | * 15m 49 | */ 50 | var isSymmetric = function(root) { 51 | if (!root) return true; 52 | 53 | let queue = [root.left, root.right]; 54 | while (queue.length > 0) { 55 | let t1 = queue.shift(); 56 | let t2 = queue.shift(); 57 | 58 | if (!t1 && !t2) continue; 59 | if (!t1 || !t2 || t1.val !== t2.val) return false; 60 | 61 | queue.push(t1.left); 62 | queue.push(t2.right); 63 | queue.push(t1.right); 64 | queue.push(t2.left); 65 | } 66 | return true; 67 | }; 68 | -------------------------------------------------------------------------------- /102__medium__binary-tree-level-order-traversal.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). 4 | 5 | For example: 6 | Given binary tree [3,9,20,null,null,15,7], 7 | 3 8 | / \ 9 | 9 20 10 | / \ 11 | 15 7 12 | return its level order traversal as: 13 | [ 14 | [3], 15 | [9,20], 16 | [15,7] 17 | ] 18 | 19 | Follow up: Recursive solution is trivial, could you do it iteratively? 20 | 21 | */ 22 | 23 | /** 24 | * Recursive 25 | * O(n) time 26 | * O(1) space 27 | * 28 | * 25m 29 | */ 30 | var levelOrder = function(root) { 31 | let res = []; 32 | if (!root) return res; 33 | const preorder = (node, level = 0) => { 34 | if (!node) return; 35 | 36 | if (level > res.length - 1) res.push([]); 37 | 38 | res[level].push(node.val); 39 | preorder(node.left, level + 1); 40 | preorder(node.right, level + 1); 41 | }; 42 | preorder(root); 43 | return res; 44 | }; 45 | 46 | /** 47 | * Iteratively using queue 48 | * O(n) time 49 | * O(n) space (max size of queue is the level max node) 50 | * 51 | * 10m 52 | */ 53 | var levelOrder = function(root) { 54 | let res = []; 55 | let queue = []; 56 | 57 | if (!root) return res; 58 | queue.push(root); 59 | 60 | while (queue.length > 0) { 61 | let lvlen = queue.length; 62 | let curr = []; 63 | for (let i = 0; i < lvlen; i++) { 64 | let node = queue.shift(); 65 | curr.push(node.val); 66 | if (node.left) queue.push(node.left); 67 | if (node.right) queue.push(node.right); 68 | } 69 | res.push(curr); 70 | } 71 | 72 | return res; 73 | }; 74 | -------------------------------------------------------------------------------- /104__easy__maximum-depth-of-binary-tree.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, find its maximum depth. 4 | 5 | The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 6 | 7 | Note: A leaf is a node with no children. 8 | 9 | Example: 10 | 11 | Given binary tree [3,9,20,null,null,15,7], 12 | 13 | 3 14 | / \ 15 | 9 20 16 | / \ 17 | 15 7 18 | return its depth = 3. 19 | 20 | */ 21 | 22 | /** 23 | * Top-Down (DFS traversal?) 24 | * O(n) time (we visit each node exactly once) 25 | * O(log(n)) space 26 | * 27 | * 20m 28 | */ 29 | var maxDepth = function(root) { 30 | if (!root) return 0; 31 | 32 | let max = 1; 33 | topDown(root, max, 0); 34 | return max; 35 | 36 | function topDown(node, depth) { 37 | if (!node) return; 38 | 39 | if (!node.left && !node.right) { 40 | max = Math.max(max, depth); 41 | } 42 | 43 | topDown(node.left, depth + 1); 44 | topDown(node.right, depth + 1); 45 | } 46 | }; 47 | 48 | /** 49 | * Bottom-Up (DFS Divide and Conquer) 50 | * O(n) time (we visit each node exactly once) 51 | * O(log(n)) space (worst O(n)) in the worst case, the tree is completely unbalanced) 52 | * 53 | * 10m 54 | */ 55 | var maxDepth = function(root) { 56 | if (!root) return 0; 57 | 58 | let maxLeft = maxDepth(root.left); 59 | let maxRight = maxDepth(root.right); 60 | 61 | return 1 + Math.max(maxLeft, maxRight); 62 | }; 63 | 64 | /** 65 | * iteratively using Queue (BFS) 66 | * O(n) time 67 | * O(n) space (max size of queue is the height max width...) 68 | * 69 | * 15m 70 | */ 71 | var maxDepth = function(root) { 72 | let res = 0; 73 | let queue = []; 74 | if (!root) return res; 75 | 76 | queue.push(root); 77 | while (queue.length > 0) { 78 | const q = queue.length; 79 | for (let i = 0; i < q; i++) { 80 | let node = queue.shift(); 81 | if (node.left) queue.push(node.left); 82 | if (node.right) queue.push(node.right); 83 | } 84 | res++; 85 | } 86 | return res; 87 | }; 88 | -------------------------------------------------------------------------------- /105__medium__construct-binary-tree-from-preorder-and-inorder-traversal.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given preorder and inorder traversal of a tree, construct the binary tree. 4 | 5 | Note: 6 | You may assume that duplicates do not exist in the tree. 7 | 8 | For example, given 9 | 10 | preorder = [3,9,20,15,7] 11 | inorder = [9,3,15,20,7] 12 | Return the following binary tree: 13 | 14 | 3 15 | / \ 16 | 9 20 17 | / \ 18 | 15 7 19 | 20 | */ 21 | 22 | /** 23 | * 24 | * O(n^2) time (not ordered so indexOf could be O(n)) 25 | * O(n) space 26 | * 27 | * 30m ... ... 28 | */ 29 | var buildTree = function(preorder, inorder) { 30 | let p = 0; 31 | 32 | const helper = (l, r) => { 33 | if (l > r) return null; 34 | 35 | let root_val = preorder[p++]; 36 | let root = new TreeNode(root_val); 37 | 38 | let idx = inorder.indexOf(root_val); 39 | 40 | // recursion 41 | root.left = helper(l, idx - 1); 42 | root.right = helper(idx + 1, r); 43 | return root; 44 | }; 45 | 46 | return helper(0, inorder.length - 1); 47 | }; 48 | 49 | /** 50 | * 51 | * O(n) time, use hashmap to find index therefore O(n) 52 | * O(n) space 53 | * 54 | * 30m ... ... 55 | */ 56 | var buildTree = function(preorder, inorder) { 57 | let p = 0; 58 | let mp = {}; 59 | for (let i = 0; i < inorder.length; i++) { 60 | mp[inorder[i]] = i; 61 | } 62 | 63 | const helper = (l, r) => { 64 | if (l > r) return null; 65 | 66 | let root_val = preorder[p++]; 67 | let root = new TreeNode(root_val); 68 | 69 | let idx = mp[root_val]; 70 | 71 | // recursion 72 | root.left = helper(l, idx - 1); 73 | root.right = helper(idx + 1, r); 74 | return root; 75 | }; 76 | 77 | return helper(0, inorder.length - 1); 78 | }; 79 | -------------------------------------------------------------------------------- /106__medium__construct-binary-tree-from-inorder-and-postorder-traversal.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given inorder and postorder traversal of a tree, construct the binary tree. 4 | 5 | Note: 6 | You may assume that duplicates do not exist in the tree. 7 | 8 | For example, given 9 | 10 | inorder = [9,3,15,20,7] 11 | postorder = [9,15,7,20,3] 12 | Return the following binary tree: 13 | 14 | 3 15 | / \ 16 | 9 20 17 | / \ 18 | 15 7 19 | 20 | */ 21 | 22 | /** 23 | * 24 | * O(n) time (use hashmap for search instead of linear search) 25 | * O(n) space 26 | * 27 | * 20m 28 | * 29 | * inorder : left root right 30 | * postorder : left right root 31 | * 32 | */ 33 | var buildTree = function(inorder, postorder) { 34 | let p = postorder.length - 1; 35 | let map = {}; 36 | for (let i = 0; i < inorder.length; i++) { 37 | map[inorder[i]] = i; 38 | } 39 | 40 | const helper = (l, r) => { 41 | if (l > r) return null; 42 | 43 | let root_val = postorder[p--]; 44 | let root = new TreeNode(root_val); 45 | 46 | let idx = map[root_val]; 47 | 48 | root.right = helper(idx + 1, r); 49 | root.left = helper(l, idx - 1); 50 | return root; 51 | }; 52 | 53 | return helper(0, p); 54 | }; 55 | -------------------------------------------------------------------------------- /112__easy__path-sum.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum. 4 | 5 | Note: A leaf is a node with no children. 6 | 7 | Example: 8 | 9 | Given the below binary tree and sum = 22, 10 | 11 | 5 12 | / \ 13 | 4 8 14 | / / \ 15 | 11 13 4 16 | / \ \ 17 | 7 2 1 18 | return true, as there exist a root-to-leaf path 5->4->11->2 which sum is 22. 19 | 20 | */ 21 | 22 | /** 23 | * 24 | * O(n) time 25 | * O(n) space 26 | * 27 | * 12m 28 | */ 29 | var hasPathSum = function(root, sum) { 30 | let found = false; 31 | 32 | const topDown = (node, curr = 0) => { 33 | if (found || !node) return; 34 | curr += node.val; 35 | 36 | if (node.left == null && node.right == null) { 37 | found = curr == sum ? true : false; 38 | return; 39 | } 40 | if (node.left !== null) topDown(node.left, curr); 41 | if (node.right !== null) topDown(node.right, curr); 42 | }; 43 | 44 | topDown(root); 45 | 46 | return found; 47 | }; 48 | 49 | /* 50 | TODO - use iterative, queue + while loop 51 | */ 52 | -------------------------------------------------------------------------------- /116__medium__populating-next-right-pointers-in-each-node.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree 4 | 5 | struct TreeLinkNode { 6 | TreeLinkNode *left; 7 | TreeLinkNode *right; 8 | TreeLinkNode *next; 9 | } 10 | Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL. 11 | 12 | Initially, all next pointers are set to NULL. 13 | 14 | Note: 15 | 16 | You may only use constant extra space. 17 | Recursive approach is fine, implicit stack space does not count as extra space for this problem. 18 | You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children). 19 | Example: 20 | 21 | Given the following perfect binary tree, 22 | 23 | 1 24 | / \ 25 | 2 3 26 | / \ / \ 27 | 4 5 6 7 28 | After calling your function, the tree should look like: 29 | 30 | 1 -> NULL 31 | / \ 32 | 2 -> 3 -> NULL 33 | / \ / \ 34 | 4->5->6->7 -> NULL 35 | 36 | */ 37 | 38 | /** 39 | * BFS 40 | * O(n) time 41 | * O(n) space 42 | * 43 | * 30m 44 | */ 45 | var connect = function(num) { 46 | if (!num) return; 47 | 48 | let queue = [num]; 49 | 50 | while (queue.length > 0) { 51 | let len = queue.length; 52 | for (let i = 0; i < len; i++) { 53 | let node = queue.shift(); 54 | node.next = i == len - 1 ? null : queue[0]; 55 | if (node.left !== null) queue.push(node.left); 56 | if (node.right !== null) queue.push(node.right); 57 | } 58 | } 59 | }; 60 | 61 | /** 62 | * Recursive 63 | * 64 | * O(n) time 65 | * O(1) / O(n) space because n stack size but... nah... 66 | * 67 | * 1 -> NULL 68 | * / \ 69 | * 2 -> 3 -> NULL 70 | * / \ / \ 71 | * 4 5 6 7 72 | * step1. as you can see, after first call, 2 -> 3 -> NULL 73 | * step2. root=2,left=4,right=5 then 4->5, 5-> ? (if root 2 has next, next.left=6) 74 | */ 75 | var connect = function(root) { 76 | if (!root) return; 77 | 78 | if (root.left) root.left.next = root.right; 79 | if (root.right && root.next) root.right.next = root.next.left; 80 | 81 | connect(root.left); 82 | connect(root.right); 83 | }; 84 | 85 | /** 86 | * Iterative 87 | * 88 | * O(n) time 89 | * O(1) space 90 | * 91 | * 1 -> NULL 92 | * / \ 93 | * 2 -> 3 -> NULL 94 | * / \ / \ 95 | * 4 5 6 7 96 | * Pointer 1 (level_head) traversal down(left) each level head 97 | * Pointer 2 for each level, traversal to right (whole level) 98 | */ 99 | var connect = function(root) { 100 | if (!root) return; 101 | 102 | let level_head = root; 103 | 104 | while (level_head) { 105 | let curr = level_head; // pointer of this level 106 | 107 | while (curr) { 108 | if (curr.left) curr.left.next = curr.right; 109 | if (curr.right && curr.next) curr.right.next = curr.next.left; 110 | curr = curr.next; 111 | } 112 | 113 | level_head = level_head.left; // keep moving down the level 114 | } 115 | }; 116 | -------------------------------------------------------------------------------- /117__medium__populating-next-right-pointers-in-each-node-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree 4 | 5 | struct TreeLinkNode { 6 | TreeLinkNode *left; 7 | TreeLinkNode *right; 8 | TreeLinkNode *next; 9 | } 10 | Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL. 11 | 12 | Initially, all next pointers are set to NULL. 13 | 14 | Note: 15 | 16 | You may only use constant extra space. 17 | Recursive approach is fine, implicit stack space does not count as extra space for this problem. 18 | Example: 19 | 20 | Given the following binary tree, 21 | 22 | 1 23 | / \ 24 | 2 3 25 | / \ \ 26 | 4 5 7 27 | After calling your function, the tree should look like: 28 | 29 | 1 -> NULL 30 | / \ 31 | 2 -> 3 -> NULL 32 | / \ \ 33 | 4-> 5 -> 7 -> NULL 34 | 35 | */ 36 | 37 | /** 38 | * too long... 39 | * O(n) time 40 | * O(1) space 41 | * 42 | * 30m 43 | */ 44 | var connect = function(root) { 45 | if (!root) return; 46 | 47 | let level_head = root; 48 | 49 | while (level_head) { 50 | let curr = level_head; // pointer of this level 51 | 52 | while (curr) { 53 | // left ? 54 | if (curr.left && curr.right) curr.left.next = curr.right; 55 | else if (curr.left && curr.next) { 56 | let left = curr.left; 57 | let next = curr.next; 58 | while (next) { 59 | if (next.left) { 60 | left.next = next.left; 61 | break; 62 | } 63 | if (next.right) { 64 | left.next = next.right; 65 | break; 66 | } 67 | next = next.next; 68 | } 69 | } 70 | // right ? 71 | if (curr.right && curr.next) { 72 | let right = curr.right; 73 | let next = curr.next; 74 | while (next) { 75 | if (next.left) { 76 | right.next = next.left; 77 | break; 78 | } 79 | if (next.right) { 80 | right.next = next.right; 81 | break; 82 | } 83 | next = next.next; 84 | } 85 | } 86 | curr = curr.next; 87 | } 88 | 89 | // keep moving down the level 90 | while (level_head) { 91 | if (level_head.left) { 92 | level_head = level_head.left; 93 | break; 94 | } 95 | if (level_head.right) { 96 | level_head = level_head.right; 97 | break; 98 | } 99 | level_head = level_head.next; 100 | } 101 | } 102 | }; 103 | 104 | /** 105 | * shorter but still ... hmm 106 | * O(n) time 107 | * O(1) space 108 | * 109 | * 30m 110 | */ 111 | var connect = function(root) { 112 | if (!root) return; 113 | 114 | let level_head = root; 115 | 116 | while (level_head) { 117 | let curr = level_head; // pointer of this level 118 | let next_head = null; 119 | 120 | while (curr) { 121 | // left 122 | if (curr.left) { 123 | if (!next_head) next_head = curr.left; 124 | 125 | if (curr.right) curr.left.next = curr.right; 126 | else { 127 | let next = curr.next; 128 | while (next) { 129 | if (next.left || next.right) { 130 | curr.left.next = next.left || next.right; 131 | break; 132 | } 133 | next = next.next; 134 | } 135 | } 136 | } 137 | // right 138 | if (curr.right) { 139 | if (!next_head) next_head = curr.right; 140 | 141 | let next = curr.next; 142 | while (next) { 143 | if (next.left || next.right) { 144 | curr.right.next = next.left || next.right; 145 | break; 146 | } 147 | next = next.next; 148 | } 149 | } 150 | curr = curr.next; 151 | } 152 | 153 | // keep moving down the level 154 | level_head = next_head; 155 | } 156 | }; 157 | -------------------------------------------------------------------------------- /119__easy__pascals_triangle_ii.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} rowIndex 3 | * @return {number[]} 4 | */ 5 | var getRow = function(rowIndex) { 6 | let res = new Array(rowIndex + 1).fill(0); 7 | res[0] = 1; 8 | /* 9 | 1 10 | 1,1 11 | 1,2,1 12 | 1,3,3,1 13 | 1,4,6,4,1 14 | */ 15 | for (let i = 0; i < res.length; i++) { 16 | for (let j = i; j > 0; j--) { 17 | if (j === i) res[j] = 1; 18 | else { 19 | res[j] = res[j] + res[j - 1]; 20 | } 21 | } 22 | } 23 | return res; 24 | }; 25 | -------------------------------------------------------------------------------- /121__easy__best-time-to-buy-and-sell-stock.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Say you have an array for which the ith element is the price of a given stock on day i. 4 | 5 | If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit. 6 | 7 | Note that you cannot sell a stock before you buy one. 8 | 9 | Example 1: 10 | 11 | Input: [7,1,5,3,6,4] 12 | Output: 5 13 | Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. 14 | Not 7-1 = 6, as selling price needs to be larger than buying price. 15 | Example 2: 16 | 17 | Input: [7,6,4,3,1] 18 | Output: 0 19 | Explanation: In this case, no transaction is done, i.e. max profit = 0. 20 | 21 | */ 22 | 23 | /** 24 | * 25 | * O(n) time 26 | * O(1) space 27 | * 28 | * 10m 29 | */ 30 | // you can only make one buy and one sell 31 | var maxProfit = function(prices) { 32 | let buy = 0; 33 | let max = 0; 34 | for (let i = 0; i < prices.length; i++) { 35 | if (prices[i] < prices[buy]) { 36 | buy = i; 37 | } else { 38 | max = Math.max(max, prices[i] - prices[buy]); 39 | } 40 | } 41 | return max; 42 | }; 43 | -------------------------------------------------------------------------------- /122__easy__best-time-to-buy-and-sell-stock-ii.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Say you have an array for which the ith element is the price of a given stock on day i. 4 | 5 | Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times). 6 | 7 | Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). 8 | 9 | Example 1: 10 | 11 | Input: [7,1,5,3,6,4] 12 | Output: 7 13 | Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4. 14 | Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3. 15 | Example 2: 16 | 17 | Input: [1,2,3,4,5] 18 | Output: 4 19 | Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4. 20 | Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are 21 | engaging multiple transactions at the same time. You must sell before buying again. 22 | Example 3: 23 | 24 | Input: [7,6,4,3,1] 25 | Output: 0 26 | Explanation: In this case, no transaction is done, i.e. max profit = 0. 27 | 28 | */ 29 | /** 30 | * 31 | * O(n) time 32 | * O(1) space 33 | * 34 | * 10m 35 | */ 36 | var maxProfit = function(prices) { 37 | if (prices.length < 2) return 0; 38 | 39 | let max = 0; 40 | for (let i = 0; i < prices.length - 1; i++) { 41 | if (prices[i] < prices[i+1]) { 42 | max += prices[i+1] - prices[i]; 43 | } 44 | } 45 | 46 | return max; 47 | }; -------------------------------------------------------------------------------- /134__medium__binary-tree-inorder-traversal.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, return the inorder traversal of its nodes' values. 4 | 5 | Example: 6 | 7 | Input: [1,null,2,3] 8 | 1 9 | \ 10 | 2 11 | / 12 | 3 13 | 14 | Output: [1,3,2] 15 | Follow up: Recursive solution is trivial, could you do it iteratively? 16 | 17 | */ 18 | 19 | /** 20 | * Recursive 21 | * O(n) time 22 | * O(n) space 23 | * 24 | * 2m 25 | */ 26 | var inorderTraversal = function(root) { 27 | let res = []; 28 | 29 | if (!root) return res; 30 | 31 | const inorder = node => { 32 | if (!node) return; 33 | 34 | inorder(node.left); 35 | res.push(node.val); 36 | inorder(node.right); 37 | }; 38 | 39 | inorder(root); 40 | return res; 41 | }; 42 | 43 | /** 44 | * Using Stack 45 | * O(n) time 46 | * O(n) space 47 | * 48 | * 25m 49 | */ 50 | var inorderTraversal = function(root) { 51 | if (!root) return []; 52 | 53 | let res = []; 54 | let st = []; 55 | let curr = root; 56 | 57 | while (curr || st.length > 0) { 58 | while (curr) { 59 | st.push(curr); 60 | curr = curr.left; 61 | } 62 | curr = st.pop(); 63 | res.push(curr.val); 64 | curr = curr.right; 65 | } 66 | return res; 67 | }; 68 | -------------------------------------------------------------------------------- /136__easy__single_number.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given a non-empty array of integers, every element appears twice except for one. Find that single one. 4 | 5 | Note: 6 | 7 | Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory? 8 | 9 | Example 1: 10 | 11 | Input: [2,2,1] 12 | Output: 1 13 | Example 2: 14 | 15 | Input: [4,1,2,1,2] 16 | Output: 4 17 | 18 | */ 19 | /** 20 | * 21 | * O(n) time 22 | * O(1) space 23 | * 24 | * 10m 25 | */ 26 | var singleNumber = function (nums) { 27 | let res = nums[0]; 28 | for (let i = 1; i < nums.length; i++) { 29 | res ^= nums[i]; 30 | } 31 | return res; 32 | }; 33 | -------------------------------------------------------------------------------- /144__medium__binary-tree-preorder-traversal.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, return the preorder traversal of its nodes' values. 4 | 5 | Example: 6 | 7 | Input: [1,null,2,3] 8 | 1 9 | \ 10 | 2 11 | / 12 | 3 13 | 14 | Output: [1,2,3] 15 | Follow up: Recursive solution is trivial, could you do it iteratively? 16 | 17 | */ 18 | 19 | /** 20 | * 21 | * Recursive 22 | * 23 | * O(n) time 24 | * O(n) space 25 | * 26 | * 3m 27 | */ 28 | var preorderTraversal = function(root) { 29 | let res = []; 30 | const preorder = node => { 31 | if (!node) return; 32 | 33 | res.push(node.val); 34 | preorder(node.left); 35 | preorder(node.right); 36 | }; 37 | preorder(root); 38 | return res; 39 | }; 40 | 41 | /** 42 | * 43 | * using Stack 44 | * 45 | * O(n) time 46 | * O(n) space 47 | * 48 | * 3m 49 | */ 50 | var preorderTraversal = function(root) { 51 | if (!root) return []; 52 | 53 | let res = []; 54 | let st = [root]; 55 | 56 | while (st.length > 0) { 57 | let node = st.pop(); 58 | res.push(node.val); 59 | if (node.right) st.push(node.right); 60 | if (node.left) st.push(node.left); 61 | } 62 | 63 | return res; 64 | }; 65 | -------------------------------------------------------------------------------- /145__hard__binary-tree-postorder-traversal.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, return the postorder traversal of its nodes' values. 4 | 5 | Example: 6 | 7 | Input: [1,null,2,3] 8 | 1 9 | \ 10 | 2 11 | / 12 | 3 13 | 14 | Output: [3,2,1] 15 | Follow up: Recursive solution is trivial, could you do it iteratively? 16 | 17 | */ 18 | 19 | /** 20 | * Recursive 21 | * O(n) time 22 | * O(n) space 23 | * 24 | * 3m 25 | */ 26 | var postorderTraversal = function(root) { 27 | if (!root) return []; 28 | 29 | let res = []; 30 | const postorder = node => { 31 | if (!node) return; 32 | 33 | postorder(node.left); 34 | postorder(node.right); 35 | res.push(node.val); 36 | }; 37 | postorder(root); 38 | return res; 39 | }; 40 | 41 | /** 42 | * Using Stack 43 | * O(n) time 44 | * O(n) space 45 | * 46 | * 15m 47 | */ 48 | var postorderTraversal = function(root) { 49 | let res = []; 50 | let st = []; 51 | 52 | if (!root) return res; 53 | st.push(root); 54 | while (st.length > 0) { 55 | let node = st.pop(); 56 | res.unshift(node.val); 57 | if (node.left) st.push(node.left); 58 | if (node.right) st.push(node.right); 59 | } 60 | return res; 61 | }; 62 | 63 | /** 64 | * Using Stack 65 | * O(n) time 66 | * O(n) space 67 | * 68 | * 15m 69 | */ 70 | var postorderTraversal = function(root) { 71 | let res = []; 72 | let st = []; 73 | 74 | if (!root) return res; 75 | st.push(root); 76 | while (st.length > 0) { 77 | let node = st.pop(); 78 | res.push(node.val); 79 | if (node.left) st.push(node.left); 80 | if (node.right) st.push(node.right); 81 | } 82 | return res.reverse(); 83 | }; 84 | -------------------------------------------------------------------------------- /151__medium__reverse_words_in_a_string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} str 3 | * @returns {string} 4 | */ 5 | 6 | /** 7 | * 8 | * O(n) time 9 | * O(1) space 10 | * 11 | */ 12 | var reverseWords = function(str) { 13 | str = str.trim().replace(/\s\s+/g, " "); 14 | str = str.split(" "); 15 | let lo = 0; 16 | let hi = str.length - 1; 17 | while (lo < hi) { 18 | [str[lo], str[hi]] = [str[hi], str[lo]]; 19 | lo++; 20 | hi--; 21 | } 22 | return str.join(" "); 23 | }; 24 | -------------------------------------------------------------------------------- /169__easy__majority-element.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times. 4 | 5 | You may assume that the array is non-empty and the majority element always exist in the array. 6 | 7 | Example 1: 8 | 9 | Input: [3,2,3] 10 | Output: 3 11 | Example 2: 12 | 13 | Input: [2,2,1,1,1,2,2] 14 | Output: 2 15 | 16 | */ 17 | 18 | /** 19 | * Because we know majority element is more than 50%, it will always win the count 20 | * O(n) time 21 | * O(1) space 22 | * 23 | * 10m 24 | * 25 | * Runtime: 60 ms, faster than 98.78% 26 | * Memory Usage: 37.1 MB, less than 97.09% 27 | * 28 | */ 29 | var majorityElement = function(nums) { 30 | let count = 1; 31 | let curr_num = nums[0]; 32 | 33 | for (let i = 1; i < nums.length; i++) { 34 | if (curr_num == nums[i]) count++; 35 | else count--; 36 | 37 | if (count === 0) { 38 | count = 1; 39 | curr_num = nums[i]; 40 | } 41 | } 42 | return curr_num; 43 | }; 44 | 45 | /** 46 | * Use hashmap, this is slower than 1st one and using O(n) space 47 | * 48 | * O(n) time 49 | * O(n) space 50 | * 51 | * 10m 52 | */ 53 | var majorityElement = function(nums) { 54 | let map = {}; 55 | let n = nums.length; 56 | let half = ~~(n/2); 57 | 58 | for (let i = 0; i < n; i++) { 59 | let num = nums[i]; 60 | 61 | map[num] = (map[num] || 0) + 1; 62 | if (map[num] > half ) { 63 | return num; 64 | } 65 | } 66 | return false; 67 | }; -------------------------------------------------------------------------------- /170__easy__two-sum-iii-data-structure-design.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Design and implement a TwoSum class. It should support the following operations: add and find. 4 | 5 | add - Add the number to an internal data structure. 6 | find - Find if there exists any pair of numbers which sum is equal to the value. 7 | 8 | Example 1: 9 | 10 | add(1); add(3); add(5); 11 | find(4) -> true 12 | find(7) -> false 13 | Example 2: 14 | 15 | add(3); add(1); add(2); 16 | find(3) -> true 17 | find(6) -> false 18 | 19 | */ 20 | 21 | /** 22 | * use hashmap for add, use loop for find 23 | * O(1) for add 24 | * O(n) for find 25 | * O(n) space 26 | * 27 | * 6m 28 | * 29 | * I don't think you should store all combinations here 30 | * the space you need is n^2 and add become O(n) even though your find become O(1) 31 | * this is still worse than the 1st solution, ex: 32 | * O(n) add 33 | * O(1) find, 34 | * O(n^2) space 35 | * 36 | */ 37 | 38 | /** 39 | * Initialize your data structure here. 40 | */ 41 | var TwoSum = function() { 42 | this.hm = new Map(); 43 | }; 44 | 45 | /** 46 | * Add the number to an internal data structure.. 47 | * @param {number} number 48 | * @return {void} 49 | */ 50 | TwoSum.prototype.add = function(number) { 51 | this.hm.set(number, (this.hm.get(number) || 0) + 1); 52 | }; 53 | 54 | /** 55 | * Find if there exists any pair of numbers which sum is equal to the value. 56 | * @param {number} value 57 | * @return {boolean} 58 | */ 59 | TwoSum.prototype.find = function(value) { 60 | for (let item of this.hm) { 61 | let target = value - item[0]; 62 | if (this.hm.has(target)) { 63 | if (target !== item[0] || this.hm.get(target) > 1) return true; 64 | } 65 | } 66 | return false; 67 | }; 68 | 69 | /** 70 | * Your TwoSum object will be instantiated and called as such: 71 | * var obj = Object.create(TwoSum).createNew() 72 | * obj.add(number) 73 | * var param_2 = obj.find(value) 74 | */ 75 | -------------------------------------------------------------------------------- /189__easy__rotate-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @param {number} k 4 | * @return {void} Do not return anything, modify nums in-place instead. 5 | */ 6 | 7 | /** 8 | * Using Reverse 9 | * O(n) time 10 | * O(1) space 11 | */ 12 | var rotate = function(nums, k) { 13 | k = k % nums.length; 14 | revs(nums, 0, nums.length - 1); 15 | revs(nums, 0, k - 1); 16 | revs(nums, k, nums.length - 1); 17 | 18 | function revs(nums, start, end) { 19 | while (start < end) { 20 | [nums[start], nums[end]] = [nums[end], nums[start]]; 21 | start++; 22 | end--; 23 | } 24 | } 25 | }; 26 | 27 | /** 28 | * Using Cyclic Replacements 29 | * O(n) time 30 | * O(1) space 31 | */ 32 | var rotate = function(nums, k) { 33 | let n = nums.length; 34 | k = k % n; 35 | let count = 0; 36 | for (let start = 0; count < nums.length; start++) { 37 | let currIdx = start; 38 | do { 39 | let nextIdx = (currIdx + k) % n; 40 | [nums[nextIdx], nums[start]] = [nums[start], nums[nextIdx]]; 41 | currIdx = nextIdx; 42 | count++; 43 | } while (start != currIdx); 44 | } 45 | }; 46 | 47 | /** 48 | * pop + unshift 49 | * O(k) time ? 50 | * O(n) space ? 51 | */ 52 | var rotate = function(nums, k) { 53 | k = k % nums.length; 54 | for (let i = 1; i <= k; i++) { 55 | nums.unshift(nums.pop()); 56 | } 57 | }; 58 | 59 | /** 60 | * copy array... 61 | * 62 | * O(n) time 63 | * O(n) space 64 | */ 65 | var rotate = function(nums, k) { 66 | k = k % nums.length; 67 | let n = nums.length; 68 | let res = new Array(n); 69 | 70 | for (let i = 0; i < n; i++) { 71 | res[i] = nums[i]; 72 | } 73 | 74 | for (let i = 0; i < n; i++) { 75 | nums[(i + k) % n] = res[i]; 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /1__easy__two-sum.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given an array of integers, return indices of the two numbers such that they add up to a specific target. 4 | 5 | You may assume that each input would have exactly one solution, and you may not use the same element twice. 6 | 7 | Example: 8 | 9 | Given nums = [2, 7, 11, 15], target = 9, 10 | 11 | Because nums[0] + nums[1] = 2 + 7 = 9, 12 | return [0, 1]. 13 | 14 | */ 15 | 16 | /** 17 | * @param 18 | * @return 19 | */ 20 | 21 | /** 22 | * 23 | * O(n) time 24 | * O(n) space 25 | * 26 | * 5m 27 | */ 28 | var twoSum = function (nums, target) { 29 | let map = {}; 30 | 31 | for (let i = 0; i < nums.length; i++) { 32 | if (map[nums[i]] !== undefined) return [map[nums[i]], i]; 33 | map[target - nums[i]] = i; 34 | } 35 | 36 | return false 37 | }; 38 | 39 | var twoSum = function (nums, target) { 40 | let map = new Map(); 41 | 42 | for (let i = 0; i < nums.length; i++) { 43 | if (map.has(nums[i])) return [map.get(nums[i]), i]; 44 | map.set(target - nums[i], i); 45 | } 46 | return false 47 | }; 48 | -------------------------------------------------------------------------------- /202__easy__happy-number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number} n 3 | * @return {boolean} 4 | */ 5 | /** 6 | * 7 | * O(n) time ??? 8 | * O(n) space ??? 9 | * 10 | * 15m 11 | */ 12 | var isHappy = function(n) { 13 | let hashset = new Set(); 14 | while (n !== 1) { 15 | if (hashset.has(n)) return false; 16 | 17 | hashset.add(n); 18 | n = getNext(n); 19 | } 20 | 21 | return true; 22 | 23 | function getNext(num) { 24 | let next = 0; 25 | while (num > 9) { 26 | let temp = num % 10; 27 | next += temp ** 2; 28 | num = ~~(num / 10); 29 | } 30 | return next + num * num; 31 | } 32 | }; 33 | 34 | /** 35 | * 36 | * O(n) time ??? 37 | * O(n) space ??? 38 | * 39 | * 5m 40 | */ 41 | var isHappy = function(n) { 42 | let hashset = new Set(); 43 | while (n !== 1) { 44 | if (hashset.has(n)) return false; 45 | 46 | hashset.add(n); 47 | 48 | let tmp = String(n); 49 | let next = 0; 50 | for (let i = 0; i < tmp.length; i++) { 51 | next += (+tmp[i]) ** 2; 52 | } 53 | n = next; 54 | } 55 | 56 | return true; 57 | }; 58 | -------------------------------------------------------------------------------- /205__easy__isomorphic-strings.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @param {string} t 4 | * @return {boolean} 5 | */ 6 | 7 | /** 8 | * 9 | * O(n) time 10 | * O(n) space 11 | * 12 | * 10m 13 | */ 14 | var isIsomorphic = function(s, t) { 15 | if (s.length !== t.length) { 16 | return false; 17 | } 18 | 19 | let mapT = {}; 20 | let mapS = {}; 21 | 22 | for (let i = 0; i < s.length; i++) { 23 | // s map to t (two way map) 24 | if (mapS[s[i]] === undefined && mapT[t[i]] === undefined) { 25 | mapS[s[i]] = t[i]; 26 | mapT[t[i]] = s[i]; 27 | } else if (mapS[s[i]] !== t[i]) { 28 | return false; 29 | } 30 | } 31 | return true; 32 | }; 33 | -------------------------------------------------------------------------------- /206__easy__reverse-linked-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Reverse a singly linked list. 4 | 5 | Example: 6 | 7 | Input: 1->2->3->4->5->NULL 8 | Output: 5->4->3->2->1->NULL 9 | 10 | Follow up: 11 | A linked list can be reversed either iteratively or recursively. Could you implement both? 12 | 13 | */ 14 | /** 15 | * Definition for singly-linked list. 16 | * function ListNode(val) { 17 | * this.val = val; 18 | * this.next = null; 19 | * } 20 | */ 21 | /** 22 | * @param {ListNode} head 23 | * @return {ListNode} 24 | */ 25 | /** 26 | * 27 | * O(n) time 28 | * O(1) space 29 | * Runtime: 56 ms, faster than 100.00% 30 | */ 31 | var reverseList = function(head) { 32 | let prev = null; 33 | while (head !== null) { 34 | let next = head.next; // hold next node 35 | head.next = prev; // reverse this and next (next -> curr) 36 | prev = head; // head is the prev of next now 37 | head = next; // move to next node (continue reverse) 38 | } 39 | return prev; 40 | }; 41 | /** 42 | * 43 | * O(n) time 44 | * O(n) space 45 | * Runtime: 56 ms, faster than 100.00% 46 | */ 47 | var reverseList = function(head) { 48 | if (!head) return null; // end of linked list 49 | if (head.next === null) return head; // last node in linked list 50 | 51 | let newHead = reverseList(head.next); // find the head of reversed linked list 52 | 53 | head.next.next = head; // reverse (next -> curr) 54 | head.next = null; // curr next should be none 55 | 56 | return newHead; 57 | }; 58 | -------------------------------------------------------------------------------- /217__easy__contains-duplicate.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {boolean} 4 | */ 5 | 6 | /** 7 | * 8 | * O(n) time 9 | * O(n) space 10 | * 11 | * 2m 12 | */ 13 | var containsDuplicate = function(nums) { 14 | let map = new Map(); 15 | for (let i = 0; i < nums.length; i++) { 16 | if (map.has(nums[i])) return true; 17 | map.set(nums[i], 1); 18 | } 19 | return false; 20 | }; 21 | 22 | /** 23 | * 24 | * O(n) time 25 | * O(1) space 26 | * 27 | * 1m 28 | */ 29 | var containsDuplicate = function(nums) { 30 | let st = new Set(nums); 31 | return st.size !== nums.length; 32 | }; 33 | 34 | /** 35 | * 36 | * O(nlogn) time (depend on the data, could also use radix sort which is n+k) 37 | * O(1) space (quick sort) 38 | * 39 | * 3m 40 | * 41 | */ 42 | var containsDuplicate = function(nums) { 43 | nums.sort((a, b) => a - b); 44 | for (let i = 1; i < nums.length; i++) { 45 | if (nums[i - 1] === nums[i]) return true; 46 | } 47 | return false; 48 | }; 49 | -------------------------------------------------------------------------------- /219__easy__contains-duplicate-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given an array of integers and an integer k, 4 | find out whether there are two distinct indices i and j 5 | in the array such that nums[i] = nums[j] and 6 | the absolute difference between i and j is at most k. 7 | 8 | Example 1: 9 | 10 | Input: nums = [1,2,3,1], k = 3 11 | Output: true 12 | Example 2: 13 | 14 | Input: nums = [1,0,1,1], k = 1 15 | Output: true 16 | Example 3: 17 | 18 | Input: nums = [1,2,3,1,2,3], k = 2 19 | Output: false 20 | 21 | */ 22 | 23 | /** 24 | * @param {number[]} nums 25 | * @param {number} k 26 | * @return {boolean} 27 | */ 28 | 29 | /** 30 | * 31 | * O(n) time 32 | * O(n) space 33 | * 34 | * 5m 35 | */ 36 | var containsNearbyDuplicate = function(nums, k) { 37 | let map = new Map(); 38 | for (let i = 0; i < nums.length; i++) { 39 | if (map.has(nums[i])) { 40 | if (i - map.get(nums[i]) <= k) return true; 41 | } 42 | map.set(nums[i], i); 43 | } 44 | return false; 45 | }; 46 | -------------------------------------------------------------------------------- /237__easy__delete-node-in-a-linked-list.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | Write a function to delete a node (except the tail) in a singly linked list, given only access to that node. 4 | 5 | Given linked list -- head = [4,5,1,9], which looks like following: 6 | 7 | Example 1: 8 | 9 | Input: head = [4,5,1,9], node = 5 10 | Output: [4,1,9] 11 | Explanation: You are given the second node with value 5, the linked list should become 4 -> 1 -> 9 after calling your function. 12 | Example 2: 13 | 14 | Input: head = [4,5,1,9], node = 1 15 | Output: [4,5,9] 16 | Explanation: You are given the third node with value 1, the linked list should become 4 -> 5 -> 9 after calling your function. 17 | 18 | 19 | Note: 20 | 21 | The linked list will have at least two elements. 22 | All of the nodes' values will be unique. 23 | The given node will not be the tail and it will always be a valid node of the linked list. 24 | Do not return anything from your function. 25 | 26 | */ 27 | 28 | /** 29 | * 30 | * O(n) time 31 | * O(1) space 32 | * 33 | * 20m (10sec next time...) 34 | */ 35 | var deleteNode = function(node) { 36 | // very tricky but interesting! 37 | node.val = node.next.val; 38 | node.next = node.next.next; 39 | }; 40 | -------------------------------------------------------------------------------- /238__medium__product-of-array-except-self.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given an array nums of n integers where n > 1, return an array output such that output[i] is equal to the product of all the elements of nums except nums[i]. 4 | 5 | Example: 6 | 7 | Input: [1,2,3,4] 8 | Output: [24,12,8,6] 9 | Note: Please solve it without division and in O(n). 10 | 11 | Follow up: 12 | Could you solve it with constant space complexity? (The output array does not count as extra space for the purpose of space complexity analysis.) 13 | 14 | */ 15 | 16 | /** 17 | * 18 | * O(n) time 19 | * O(n) space 20 | * 21 | */ 22 | var productExceptSelf = function(nums) { 23 | if (!nums || nums.length === 0) return nums; 24 | 25 | let res = new Array(nums.length).fill(1); 26 | 27 | for (let i = 1; i < nums.length; i++) { 28 | res[i] = res[i-1] * nums[i-1]; 29 | } 30 | 31 | let right = nums[nums.length-1]; 32 | for (let i = nums.length - 2; i >= 0; i--) { 33 | res[i] = res[i] * right; 34 | right = right * nums[i]; 35 | } 36 | 37 | return res; 38 | }; -------------------------------------------------------------------------------- /249__medium__group-shifted-strings.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a string, we can "shift" each of its letter to its successive letter, for example: "abc" -> "bcd". We can keep "shifting" which forms the sequence: 4 | 5 | "abc" -> "bcd" -> ... -> "xyz" 6 | Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting sequence. 7 | 8 | Example: 9 | 10 | Input: ["abc", "bcd", "acef", "xyz", "az", "ba", "a", "z"], 11 | Output: 12 | [ 13 | ["abc","bcd","xyz"], 14 | ["az","ba"], 15 | ["acef"], 16 | ["a","z"] 17 | ] 18 | 19 | */ 20 | 21 | /** 22 | * @param {string[]} strings 23 | * @return {string[][]} 24 | */ 25 | 26 | /** 27 | * 28 | * O(nk) time (for n string, avg length k) 29 | * O(nk) space 30 | * 31 | * 30m 32 | */ 33 | var groupStrings = function(strings) { 34 | let map = {}; 35 | let res = []; 36 | 37 | for (let i = 0; i < strings.length; i++) { 38 | let k = getKey(strings[i]); 39 | map[k] = map[k] || []; 40 | map[k].push(strings[i]); 41 | } 42 | Object.values(map).forEach(group => { 43 | res.push(group); 44 | }); 45 | return res; 46 | 47 | function getKey(str) { 48 | let base = str[0].charCodeAt(); 49 | let key = ""; 50 | 51 | for (let i = 0; i < str.length; i++) { 52 | let dist = str.charCodeAt(i) - base; 53 | if (dist < 0) dist += 26; 54 | key += dist + "|"; 55 | } 56 | return key; 57 | } 58 | }; 59 | -------------------------------------------------------------------------------- /250__medium__count-univalue-subtrees.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, count the number of uni-value subtrees. 4 | 5 | A Uni-value subtree means all nodes of the subtree have the same value. 6 | 7 | Example : 8 | 9 | Input: root = [5,1,5,5,5,null,5] 10 | 11 | 5 12 | / \ 13 | 1 5 14 | / \ \ 15 | 5 5 5 16 | 17 | Output: 4 18 | 19 | */ 20 | 21 | /** 22 | * 23 | * O(n) time 24 | * O(n) space 25 | * 26 | * 20m 27 | */ 28 | var countUnivalSubtrees = function(root) { 29 | let count = 0; 30 | const postOrder = node => { 31 | if (node == null) return true; 32 | 33 | let left = postOrder(node.left); 34 | let right = postOrder(node.right); 35 | 36 | if ( 37 | left && 38 | right && 39 | (!node.left || node.left.val == node.val) && 40 | (!node.right || node.right.val == node.val) 41 | ) { 42 | count += 1; 43 | return true; 44 | } 45 | return false; 46 | }; 47 | 48 | postOrder(root); 49 | return count; 50 | }; 51 | -------------------------------------------------------------------------------- /26__easy__remove-duplicates-from-sorted-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length. 4 | 5 | Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. 6 | 7 | Example 1: 8 | 9 | Given nums = [1,1,2], 10 | 11 | Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. 12 | 13 | It doesn't matter what you leave beyond the returned length. 14 | Example 2: 15 | 16 | Given nums = [0,0,1,1,1,2,2,3,3,4], 17 | 18 | Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively. 19 | 20 | It doesn't matter what values are set beyond the returned length. 21 | 22 | 23 | */ 24 | 25 | /** 26 | * 27 | * O(n) time 28 | * O(1) space 29 | * 30 | * 10m 31 | */ 32 | var removeDuplicates = function (nums) { 33 | let left = 0; 34 | for (let i = 0; i < nums.length; i++) { 35 | if (nums[i] !== nums[left]) { 36 | left++; 37 | nums[left] = nums[i]; 38 | } 39 | } 40 | return left + 1; 41 | }; 42 | -------------------------------------------------------------------------------- /283__easy__move-zeroes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums 3 | * @return {void} Do not return anything, modify nums in-place instead. 4 | */ 5 | 6 | /** 7 | * 8 | * O(n) time 9 | * O(1) space 10 | * 11 | * 5m 12 | */ 13 | var moveZeroes = function(nums) { 14 | let idx = 0; 15 | for (let i = 0; i < nums.length; i++) { 16 | if (nums[i] !== 0) { 17 | [nums[i], nums[idx]] = [nums[idx], nums[i]]; 18 | idx++; 19 | } 20 | while (nums[idx] !== 0 && idx < i) { 21 | idx++; 22 | } 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /288__medium__unique-word-abbreviation.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param 3 | * @return 4 | */ 5 | 6 | /** 7 | * 8 | * O(n) time preprocess 9 | * O(n) space for map 10 | * O(1) for isUnique() call 11 | * 12 | * 45m 13 | */ 14 | 15 | /* 16 | =================== solution 1 (115ms) =================== 17 | */ 18 | /** 19 | * @param {string[]} NOTE: dictionary is unique here!!! 20 | */ 21 | var ValidWordAbbr = function(dictionary) { 22 | this.map = new Map(); 23 | for (let i = 0; i < dictionary.length; i++) { 24 | let w = dictionary[i]; 25 | if (w.length < 3) this.map.set(w, [w]); 26 | else { 27 | let key = this.toAbbr(w); 28 | let group = this.map.get(key) || []; 29 | group.push(w); 30 | this.map.set(key, group); 31 | } 32 | } 33 | }; 34 | 35 | /** 36 | * @param {string} word 37 | * @return {boolean} 38 | */ 39 | ValidWordAbbr.prototype.isUnique = function(word) { 40 | let len = word.length; 41 | if (len < 3) return true; 42 | let key = this.toAbbr(word); 43 | if (this.map.has(key)) { 44 | let group = this.map.get(key); 45 | if (group.length === 1) return group[0] === word; 46 | return false; 47 | } 48 | return true; 49 | }; 50 | 51 | ValidWordAbbr.prototype.toAbbr = word => { 52 | let len = word.length; 53 | if (len < 3) return word; 54 | return word[0] + (len - 2) + word[len - 1]; 55 | }; 56 | /** 57 | * Your ValidWordAbbr object will be instantiated and called as such: 58 | * var obj = Object.create(ValidWordAbbr).createNew(dictionary) 59 | * var param_1 = obj.isUnique(word) 60 | */ 61 | 62 | /* 63 | =================== solution 2 (96ms) =================== 64 | */ 65 | /** 66 | * @param {string[]} dictionary is unique 67 | */ 68 | var ValidWordAbbr = function(dictionary) { 69 | this.map = new Map(); 70 | for (let i = 0; i < dictionary.length; i++) { 71 | let w = dictionary[i]; 72 | if (w.length < 3) this.map.set(w, true); 73 | else { 74 | let key = this.toAbbr(w); 75 | let val = this.map.has(key) ? false : w; 76 | this.map.set(key, val); 77 | } 78 | } 79 | }; 80 | 81 | /** 82 | * @param {string} word 83 | * @return {boolean} 84 | */ 85 | ValidWordAbbr.prototype.isUnique = function(word) { 86 | let len = word.length; 87 | if (len < 3) return true; 88 | 89 | let key = this.toAbbr(word); 90 | if (this.map.has(key)) { 91 | let val = this.map.get(key); 92 | if (val === false) return false; 93 | return word === val; 94 | } 95 | return true; 96 | }; 97 | 98 | ValidWordAbbr.prototype.toAbbr = word => { 99 | let len = word.length; 100 | if (len < 3) return word; 101 | return word[0] + (len - 2) + word[len - 1]; 102 | }; 103 | 104 | /** 105 | * Your ValidWordAbbr object will be instantiated and called as such: 106 | * var obj = Object.create(ValidWordAbbr).createNew(dictionary) 107 | * var param_1 = obj.isUnique(word) 108 | */ 109 | -------------------------------------------------------------------------------- /344__easy__reverse-string.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Write a function that reverses a string. The input string is given as an array of characters char[]. 4 | 5 | Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. 6 | 7 | You may assume all the characters consist of printable ascii characters. 8 | 9 | Example 1: 10 | 11 | Input: ["h","e","l","l","o"] 12 | Output: ["o","l","l","e","h"] 13 | Example 2: 14 | 15 | Input: ["H","a","n","n","a","h"] 16 | Output: ["h","a","n","n","a","H"] 17 | 18 | */ 19 | /** 20 | * 21 | * O(n) time 22 | * O(1) space 23 | * 24 | * 5m 25 | */ 26 | var reverseString = function (s) { 27 | let lo = 0; 28 | let hi = s.length - 1; 29 | while (lo < hi) { 30 | [s[lo], s[hi]] = [s[hi], s[lo]]; 31 | lo++; 32 | hi--; 33 | } 34 | }; -------------------------------------------------------------------------------- /347__medium__top-k-frequent-elements.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a non-empty array of integers, return the k most frequent elements. 4 | 5 | Example 1: 6 | 7 | Input: nums = [1,1,1,2,2,3], k = 2 8 | Output: [1,2] 9 | Example 2: 10 | 11 | Input: nums = [1], k = 1 12 | Output: [1] 13 | Note: 14 | 15 | You may assume k is always valid, 1 ≤ k ≤ number of unique elements. 16 | Your algorithm's time complexity must be better than O(n log n), where n is the array's size. 17 | 18 | */ 19 | 20 | /** 21 | * @param {number[]} nums 22 | * @param {number} k 23 | * @return {number[]} 24 | */ 25 | var topKFrequent = function(nums, k) { 26 | let res = []; 27 | if (!nums || nums.length === 0) return res; 28 | 29 | // Count frequency of each element use hashmap, O(n) time O(n) space 30 | let map = new Map(); 31 | for (let i = 0; i < nums.length; i++) { 32 | map.set(nums[i], (map.get(nums[i]) || 0) + 1); 33 | } 34 | 35 | // new bucket size of n+1, O(n+1) time O(n+1) space 36 | let buckets = new Array(nums.length + 1).fill(null).map(() => []); 37 | 38 | // push element count into bucket, count will no bigger than n+1 so every element could fit 39 | // O(n) time 40 | for (let [num, count] of map) { 41 | buckets[count].push(num); 42 | } 43 | 44 | // O(k) time, find k element from bucket (end to start so we get top k) 45 | for (let i = buckets.length - 1; i >= 0; i--) { 46 | for (let j = 0; j < buckets[i].length; j++) { 47 | res.push(buckets[i][j]); 48 | if (res.length === k) return res; 49 | } 50 | } 51 | }; 52 | /* 53 | 54 | Bucket sort 55 | O(n) time 56 | O(n) space 57 | 58 | */ 59 | -------------------------------------------------------------------------------- /349__easy__intersection-of-two-arrays.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {number[]} nums1 3 | * @param {number[]} nums2 4 | * @return {number[]} 5 | */ 6 | 7 | /** 8 | * 9 | * O(n) time 10 | * O(n) space 11 | * 12 | * 3m 13 | */ 14 | var intersection = function(nums1, nums2) { 15 | let map = {}; 16 | let res = []; 17 | for (let i = 0; i < nums1.length; i++) { 18 | map[nums1[i]] = 1; 19 | } 20 | 21 | for (let i = 0; i < nums2.length; i++) { 22 | if (map[nums2[i]] !== undefined) { 23 | res.push(nums2[i]); 24 | delete map[nums2[i]]; 25 | } 26 | } 27 | return res; 28 | }; 29 | -------------------------------------------------------------------------------- /350__easy__intersection-of-two-arrays-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given two arrays, write a function to compute their intersection. 4 | 5 | Example 1: 6 | 7 | Input: nums1 = [1,2,2,1], nums2 = [2,2] 8 | Output: [2,2] 9 | Example 2: 10 | 11 | Input: nums1 = [4,9,5], nums2 = [9,4,9,8,4] 12 | Output: [4,9] 13 | Note: 14 | 15 | Each element in the result should appear as many times as it shows in both arrays. 16 | The result can be in any order. 17 | Follow up: 18 | 19 | What if the given array is already sorted? How would you optimize your algorithm? 20 | What if nums1's size is small compared to nums2's size? Which algorithm is better? 21 | What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once? 22 | 23 | */ 24 | 25 | /** 26 | * @param {number[]} nums1 27 | * @param {number[]} nums2 28 | * @return {number[]} 29 | */ 30 | 31 | /** 32 | * 33 | * O(n) time 34 | * O(n) space 35 | * 36 | * 10m 37 | */ 38 | var intersect = function(nums1, nums2) { 39 | let map = {}; 40 | let res = []; 41 | for (let i = 0; i < nums1.length; i++) { 42 | map[nums1[i]] = (map[nums1[i]] || 0) + 1; 43 | } 44 | for (let i = 0; i < nums2.length; i++) { 45 | if (map[nums2[i]] !== undefined && map[nums2[i]] > 0) { 46 | res.push(nums2[i]); 47 | map[nums2[i]]--; 48 | } 49 | } 50 | return res; 51 | }; 52 | -------------------------------------------------------------------------------- /359__easy__logger-rate-limiter.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Design a logger system that receive stream of messages along with its timestamps, each message should be printed if and only if it is not printed in the last 10 seconds. 4 | 5 | Given a message and a timestamp (in seconds granularity), return true if the message should be printed in the given timestamp, otherwise returns false. 6 | 7 | It is possible that several messages arrive roughly at the same time. 8 | 9 | Example: 10 | 11 | Logger logger = new Logger(); 12 | 13 | // logging string "foo" at timestamp 1 14 | logger.shouldPrintMessage(1, "foo"); returns true; 15 | 16 | // logging string "bar" at timestamp 2 17 | logger.shouldPrintMessage(2,"bar"); returns true; 18 | 19 | // logging string "foo" at timestamp 3 20 | logger.shouldPrintMessage(3,"foo"); returns false; 21 | 22 | // logging string "bar" at timestamp 8 23 | logger.shouldPrintMessage(8,"bar"); returns false; 24 | 25 | // logging string "foo" at timestamp 10 26 | logger.shouldPrintMessage(10,"foo"); returns false; 27 | 28 | // logging string "foo" at timestamp 11 29 | logger.shouldPrintMessage(11,"foo"); returns true; 30 | 31 | */ 32 | 33 | /** 34 | * Initialize your data structure here. 35 | */ 36 | var Logger = function() { 37 | this.map = new Map(); 38 | this.limit = 10; 39 | }; 40 | 41 | /** 42 | * Returns true if the message should be printed in the given timestamp, otherwise returns false. 43 | If this method returns false, the message will not be printed. 44 | The timestamp is in seconds granularity. 45 | * @param {number} timestamp 46 | * @param {string} message 47 | * @return {boolean} 48 | */ 49 | Logger.prototype.shouldPrintMessage = function(timestamp, message) { 50 | if ( 51 | !this.map.has(message) || 52 | (this.map.has(message) && this.map.get(message) <= timestamp) 53 | ) { 54 | this.map.set(message, timestamp + this.limit); 55 | return true; 56 | } 57 | return false; 58 | }; 59 | 60 | /** 61 | * Your Logger object will be instantiated and called as such: 62 | * var obj = Object.create(Logger).createNew() 63 | * var param_1 = obj.shouldPrintMessage(timestamp,message) 64 | */ 65 | -------------------------------------------------------------------------------- /36__medium__valid-sudoku.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Determine if a 9x9 Sudoku board is valid. Only the filled cells need to be validated according to the following rules: 4 | 5 | Each row must contain the digits 1-9 without repetition. 6 | Each column must contain the digits 1-9 without repetition. 7 | Each of the 9 3x3 sub-boxes of the grid must contain the digits 1-9 without repetition. 8 | 9 | The Sudoku board could be partially filled, where empty cells are filled with the character '.'. 10 | 11 | Example 1: 12 | 13 | Input: 14 | [ 15 | ["5","3",".",".","7",".",".",".","."], 16 | ["6",".",".","1","9","5",".",".","."], 17 | [".","9","8",".",".",".",".","6","."], 18 | ["8",".",".",".","6",".",".",".","3"], 19 | ["4",".",".","8",".","3",".",".","1"], 20 | ["7",".",".",".","2",".",".",".","6"], 21 | [".","6",".",".",".",".","2","8","."], 22 | [".",".",".","4","1","9",".",".","5"], 23 | [".",".",".",".","8",".",".","7","9"] 24 | ] 25 | Output: true 26 | Example 2: 27 | 28 | Input: 29 | [ 30 | ["8","3",".",".","7",".",".",".","."], 31 | ["6",".",".","1","9","5",".",".","."], 32 | [".","9","8",".",".",".",".","6","."], 33 | ["8",".",".",".","6",".",".",".","3"], 34 | ["4",".",".","8",".","3",".",".","1"], 35 | ["7",".",".",".","2",".",".",".","6"], 36 | [".","6",".",".",".",".","2","8","."], 37 | [".",".",".","4","1","9",".",".","5"], 38 | [".",".",".",".","8",".",".","7","9"] 39 | ] 40 | Output: false 41 | Explanation: Same as Example 1, except with the 5 in the top left corner being 42 | modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid. 43 | 44 | */ 45 | 46 | /** 47 | * @param {character[][]} board 48 | * @return {boolean} 49 | */ 50 | /** 51 | * 52 | * O(n) time 53 | * O(n) space (3n) 54 | * 55 | * 15m 56 | */ 57 | var isValidSudoku = function(board) { 58 | if (!board || board.length === 0 || board[0].length === 0) return false; 59 | 60 | let rows = board.length; 61 | let cols = board[0].length; 62 | let hashset = new Set(); // hashset 63 | 64 | for (let r = 0; r < rows; r++) { 65 | for (let c = 0; c < cols; c++) { 66 | let num = board[r][c]; 67 | if (num === ".") continue; 68 | 69 | let rowKey = "r" + r + "|" + num; 70 | let colKey = "c" + c + "|" + num; 71 | let gridKey = "g" + (~~(r / 3) * 3 + ~~(c / 3)) + "|" + num; 72 | if ( 73 | !hashset.has(rowKey) && 74 | !hashset.has(colKey) && 75 | !hashset.has(gridKey) 76 | ) { 77 | hashset.add(rowKey); 78 | hashset.add(colKey); 79 | hashset.add(gridKey); 80 | } else { 81 | return false; 82 | } 83 | } 84 | } 85 | return true; 86 | }; 87 | -------------------------------------------------------------------------------- /380__medium__insert-delete-getrandom-o1.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Design a data structure that supports all following operations in average O(1) time. 4 | 5 | 1. insert(val): Inserts an item val to the set if not already present. 6 | 2. remove(val): Removes an item val from the set if present. 7 | 3. getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned. 8 | 9 | Example: 10 | 11 | // Init an empty set. 12 | RandomizedSet randomSet = new RandomizedSet(); 13 | 14 | // Inserts 1 to the set. Returns true as 1 was inserted successfully. 15 | randomSet.insert(1); 16 | 17 | // Returns false as 2 does not exist in the set. 18 | randomSet.remove(2); 19 | 20 | // Inserts 2 to the set, returns true. Set now contains [1,2]. 21 | randomSet.insert(2); 22 | 23 | // getRandom should return either 1 or 2 randomly. 24 | randomSet.getRandom(); 25 | 26 | // Removes 1 from the set, returns true. Set now contains [2]. 27 | randomSet.remove(1); 28 | 29 | // 2 was already in the set, so return false. 30 | randomSet.insert(2); 31 | 32 | // Since 2 is the only number in the set, getRandom always return 2. 33 | randomSet.getRandom(); 34 | 35 | */ 36 | 37 | /** 38 | * 39 | * O(1) time 40 | * O(n) space 41 | * 42 | * 25m 43 | */ 44 | 45 | /** 46 | * Initialize your data structure here. 47 | */ 48 | var RandomizedSet = function() { 49 | this.map = new Map(); 50 | this.arr = new Array(); 51 | }; 52 | 53 | /** 54 | * Inserts a value to the set. Returns true if the set did not already contain the specified element. 55 | * @param {number} val 56 | * @return {boolean} 57 | */ 58 | RandomizedSet.prototype.insert = function(val) { 59 | if (this.map.has(val)) return false; 60 | 61 | this.arr.push(val); 62 | this.map.set(val, this.arr.length - 1); 63 | return true; 64 | }; 65 | 66 | /** 67 | * Removes a value from the set. Returns true if the set contained the specified element. 68 | * @param {number} val 69 | * @return {boolean} 70 | */ 71 | RandomizedSet.prototype.remove = function(val) { 72 | if (!this.map.has(val)) return false; 73 | 74 | let lastIdx = this.arr.length - 1; 75 | let lastVal = this.arr[lastIdx]; 76 | let delIdx = this.map.get(val); 77 | if (delIdx !== lastIdx) { 78 | this.arr[delIdx] = lastVal; 79 | this.map.set(lastVal, delIdx); 80 | } 81 | this.map.delete(val); 82 | this.arr.pop(); 83 | return true; 84 | }; 85 | 86 | /** 87 | * Get a random element from the set. 88 | * @return {number} 89 | */ 90 | RandomizedSet.prototype.getRandom = function() { 91 | return this.arr[~~(Math.random() * this.arr.length)]; 92 | }; 93 | 94 | /** 95 | * Your RandomizedSet object will be instantiated and called as such: 96 | * var obj = Object.create(RandomizedSet).createNew() 97 | * var param_1 = obj.insert(val) 98 | * var param_2 = obj.remove(val) 99 | * var param_3 = obj.getRandom() 100 | */ 101 | -------------------------------------------------------------------------------- /387__easy__first-unique-character-in-a-string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {number} 4 | */ 5 | 6 | /** 7 | * 8 | * O(n) time 9 | * O(n) space 10 | * 11 | * 10m 12 | */ 13 | var firstUniqChar = function(s) { 14 | let map = {}; 15 | for (let i = 0; i < s.length; i++) { 16 | map[s[i]] = (map[s[i]] || 0) + 1; 17 | } 18 | for (let i = 0; i < s.length; i++) { 19 | if (map[s[i]] === 1) return i; 20 | } 21 | return -1; 22 | }; 23 | -------------------------------------------------------------------------------- /3__medium__longest-substring-without-repeating-characters.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a string, find the length of the longest substring without repeating characters. 4 | 5 | Example 1: 6 | 7 | Input: "abcabcbb" 8 | Output: 3 9 | Explanation: The answer is "abc", with the length of 3. 10 | Example 2: 11 | 12 | Input: "bbbbb" 13 | Output: 1 14 | Explanation: The answer is "b", with the length of 1. 15 | Example 3: 16 | 17 | Input: "pwwkew" 18 | Output: 3 19 | Explanation: The answer is "wke", with the length of 3. 20 | Note that the answer must be a substring, "pwke" is a subsequence and not a substring. 21 | 22 | */ 23 | 24 | /** 25 | * @param {string} s 26 | * @return {number} 27 | */ 28 | var lengthOfLongestSubstring = function(s) { 29 | if (!s || s.length === 0 || s.length === 1) return s.length; 30 | 31 | let max = 0; 32 | let left = 0; 33 | let map = new Map(); 34 | 35 | for (let i = 0; i < s.length; i++) { 36 | if (map.has(s[i]) && map.get(s[i]) > 0) { 37 | while (map.get(s[i]) > 0) { 38 | map.set(s[left], map.get(s[left]) - 1); 39 | left++; 40 | } 41 | } 42 | map.set(s[i], 1); 43 | max = Math.max(max, i - left + 1); 44 | } 45 | return max; 46 | }; 47 | /** 48 | * 49 | * O(n) time (In the worst case O(2n) each character will be visited twice by i and left) 50 | * O(k) space (which is length of longest non repeating substring) 51 | * 52 | * 10m 53 | */ 54 | -------------------------------------------------------------------------------- /412__easy__fizz_buzz.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Write a program that outputs the string representation of numbers from 1 to n. 4 | 5 | But for multiples of three it should output “Fizz” instead of the number and for the multiples of five output “Buzz”. For numbers which are multiples of both three and five output “FizzBuzz”. 6 | 7 | Example: 8 | 9 | n = 15, 10 | 11 | Return: 12 | [ 13 | "1", 14 | "2", 15 | "Fizz", 16 | "4", 17 | "Buzz", 18 | "Fizz", 19 | "7", 20 | "8", 21 | "Fizz", 22 | "Buzz", 23 | "11", 24 | "Fizz", 25 | "13", 26 | "14", 27 | "FizzBuzz" 28 | ] 29 | 30 | */ 31 | /** 32 | * @param {number} n 33 | * @return {string[]} 34 | */ 35 | /** 36 | * 37 | * O(n) time 38 | * O(1) space 39 | * 40 | */ 41 | var fizzBuzz = function (n) { 42 | const res = []; 43 | for (let i = 1; i <= n; i++) { 44 | if (i % 15 === 0) res.push('FizzBuzz') 45 | else if (i % 5 === 0) res.push('Buzz') 46 | else if (i % 3 === 0) res.push('Fizz') 47 | else res.push(String(i)) 48 | } 49 | return res 50 | }; 51 | -------------------------------------------------------------------------------- /454__medium__4sum-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero. 4 | 5 | To make problem a bit easier, all A, B, C, D have same length of N where 0 ≤ N ≤ 500. All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1. 6 | 7 | Example: 8 | 9 | Input: 10 | A = [ 1, 2] 11 | B = [-2,-1] 12 | C = [-1, 2] 13 | D = [ 0, 2] 14 | 15 | Output: 16 | 2 17 | 18 | Explanation: 19 | The two tuples are: 20 | 1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0 21 | 2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0 22 | 23 | */ 24 | 25 | /** 26 | * @param {number[]} A 27 | * @param {number[]} B 28 | * @param {number[]} C 29 | * @param {number[]} D 30 | * @return {number} 31 | */ 32 | var fourSumCount = function(A, B, C, D) { 33 | let map = new Map(); 34 | let res = 0; 35 | 36 | for (let i = 0; i < A.length; i++) { 37 | for (let j = 0; j < B.length; j++) { 38 | let sum = A[i] + B[j]; 39 | map.set(sum, (map.get(sum) || 0) + 1); 40 | } 41 | } 42 | for (let i = 0; i < C.length; i++) { 43 | for (let j = 0; j < D.length; j++) { 44 | let target = -C[i] - D[j]; 45 | res += map.get(target) || 0; 46 | } 47 | } 48 | return res; 49 | }; 50 | /** 51 | * 52 | * O(n^2) time (n for length of A) 53 | * O(n^2) space 54 | * 55 | * 15m 56 | * 57 | */ 58 | -------------------------------------------------------------------------------- /461__easy__hamming-distance.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The Hamming distance between two integers is the number of positions at which the corresponding bits are different. 4 | 5 | Given two integers x and y, calculate the Hamming distance. 6 | 7 | Note: 8 | 0 ≤ x, y < 231. 9 | 10 | Example: 11 | 12 | Input: x = 1, y = 4 13 | 14 | Output: 2 15 | 16 | Explanation: 17 | 1 (0 0 0 1) 18 | 4 (0 1 0 0) 19 | ↑ ↑ 20 | 21 | The above arrows point to positions where the corresponding bits are different. 22 | 23 | */ 24 | 25 | /** 26 | * 27 | * O(n) time for n is the length of x/y 28 | * O(n) space 29 | * 30 | * Runtime: 52 ms, faster than 100.00% 31 | */ 32 | var hammingDistance = function(x, y) { 33 | let bin_diff = Number(x ^ y).toString(2); 34 | let count = 0; 35 | 36 | for (let ch of bin_diff) { 37 | if (ch == "1") count += 1; 38 | } 39 | 40 | return count; 41 | }; 42 | -------------------------------------------------------------------------------- /489__hard__robot-room-cleaner.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given a robot cleaner in a room modeled as a grid. 4 | 5 | Each cell in the grid can be empty or blocked. 6 | 7 | The robot cleaner with 4 given APIs can move forward, turn left or turn right. Each turn it made is 90 degrees. 8 | 9 | When it tries to move into a blocked cell, its bumper sensor detects the obstacle and it stays on the current cell. 10 | 11 | Design an algorithm to clean the entire room using only the 4 given APIs shown below. 12 | 13 | interface Robot { 14 | // returns true if next cell is open and robot moves into the cell. 15 | // returns false if next cell is obstacle and robot stays on the current cell. 16 | boolean move(); 17 | 18 | // Robot will stay on the same cell after calling turnLeft/turnRight. 19 | // Each turn will be 90 degrees. 20 | void turnLeft(); 21 | void turnRight(); 22 | 23 | // Clean the current cell. 24 | void clean(); 25 | } 26 | Example: 27 | 28 | Input: 29 | room = [ 30 | [1,1,1,1,1,0,1,1], 31 | [1,1,1,1,1,0,1,1], 32 | [1,0,1,1,1,1,1,1], 33 | [0,0,0,1,0,0,0,0], 34 | [1,1,1,1,1,1,1,1] 35 | ], 36 | row = 1, 37 | col = 3 38 | 39 | Explanation: 40 | All grids in the room are marked by either 0 or 1. 41 | 0 means the cell is blocked, while 1 means the cell is accessible. 42 | The robot initially starts at the position of row=1, col=3. 43 | From the top left corner, its position is one row below and three columns right. 44 | 45 | */ 46 | /** 47 | * // This is the robot's control interface. 48 | * // You should not implement it, or speculate about its implementation 49 | * function Robot() { 50 | * 51 | * // Returns true if the cell in front is open and robot moves into the cell. 52 | * // Returns false if the cell in front is blocked and robot stays in the current cell. 53 | * @return {boolean} 54 | * this.move = function() { 55 | * ... 56 | * }; 57 | * 58 | * // Robot will stay in the same cell after calling turnLeft/turnRight. 59 | * // Each turn will be 90 degrees. 60 | * @return {void} 61 | * this.turnLeft = function() { 62 | * ... 63 | * }; 64 | * 65 | * // Robot will stay in the same cell after calling turnLeft/turnRight. 66 | * // Each turn will be 90 degrees. 67 | * @return {void} 68 | * this.turnRight = function() { 69 | * ... 70 | * }; 71 | * 72 | * // Clean the current cell. 73 | * @return {void} 74 | * this.clean = function() { 75 | * ... 76 | * }; 77 | * }; 78 | */ 79 | /** 80 | * @param {Robot} robot 81 | * @return {void} 82 | */ 83 | 84 | /** 85 | * 86 | * O(n) time 87 | * O(n) space 88 | * 89 | * Runtime: 76 ms, faster than 98.80% 90 | */ 91 | var cleanRoom = function(robot) { 92 | const doneSet = new Set(); 93 | // [x, y] up, right, down, left 94 | const dirs = [[0, 1], [1, 0], [0, -1], [-1, 0]]; 95 | 96 | dfs(0, 0, 0); 97 | 98 | function dfs(lastDirIndex, x, y) { 99 | // move -> clean -> add to doneSet [x:y] 100 | robot.clean(); 101 | doneSet.add(`${x}:${y}`); 102 | // dfs 4 direction (if not visited) 103 | for (let i = 0; i < 4; i++) { 104 | let currDirIndex = (lastDirIndex + i) % 4; 105 | let xx = x + dirs[currDirIndex][0]; 106 | let yy = y + dirs[currDirIndex][1]; 107 | 108 | // if the facing grid not cleaned yet 109 | // try to move to the facing grid now 110 | if (!doneSet.has(`${xx}:${yy}`) && robot.move()) { 111 | dfs(currDirIndex, xx, yy); 112 | } 113 | 114 | robot.turnRight(); // turn right 4 time so we face the same direction as we get here 115 | } 116 | 117 | // we have done 4 directions here, move back to where we come from 118 | robot.turnRight(); 119 | robot.turnRight(); 120 | robot.move(); 121 | robot.turnRight(); 122 | robot.turnRight(); 123 | } 124 | }; 125 | -------------------------------------------------------------------------------- /49__medium__group-anagrams.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given an array of strings, group anagrams together. 4 | 5 | Example: 6 | 7 | Input: ["eat", "tea", "tan", "ate", "nat", "bat"], 8 | Output: 9 | [ 10 | ["ate","eat","tea"], 11 | ["nat","tan"], 12 | ["bat"] 13 | ] 14 | Note: 15 | 16 | All inputs will be in lowercase. 17 | The order of your output does not matter. 18 | 19 | */ 20 | 21 | /** 22 | * @param {string[]} strs 23 | * @return {string[][]} 24 | */ 25 | 26 | /** 27 | * 28 | * Time Complexity: O(NKlogK), 29 | * where N is the length of strs, 30 | * and K is the maximum length of a string in strs. 31 | * 32 | * Space Complexity: O(NK), the total information content stored in ans. 33 | * 34 | * 15m 35 | */ 36 | var groupAnagrams = function(strs) { 37 | let map = {}; 38 | let res = []; 39 | 40 | for (let i = 0; i < strs.length; i++) { 41 | let key = hashKeyFromStr(strs[i]); 42 | map[key] = map[key] || []; 43 | map[key].push(strs[i]); 44 | } 45 | for (let arr of Object.values(map)) { 46 | res.push(arr); 47 | } 48 | 49 | return res; 50 | 51 | function hashKeyFromStr(str) { 52 | return str 53 | .split("") 54 | .sort() 55 | .join(""); 56 | } 57 | }; 58 | 59 | /** 60 | * 61 | * O(NK) time 62 | * O(NK) space 63 | * 64 | * 30m (you need to get the primes list...) 65 | */ 66 | var groupAnagrams = function(strs) { 67 | const map = new Map(); 68 | const primes = [ 69 | 2, 70 | 3, 71 | 5, 72 | 7, 73 | 11, 74 | 13, 75 | 17, 76 | 19, 77 | 23, 78 | 29, 79 | 31, 80 | 37, 81 | 41, 82 | 43, 83 | 47, 84 | 53, 85 | 59, 86 | 61, 87 | 67, 88 | 71, 89 | 73, 90 | 79, 91 | 83, 92 | 89, 93 | 97, 94 | 101, 95 | 107 96 | ]; 97 | 98 | strs.forEach(str => { 99 | let key = 1; 100 | for (let i = 0; i < str.length; i++) { 101 | key = primes[str.charCodeAt(i) - "a".charCodeAt()] * key; 102 | } 103 | if (map.has(key)) { 104 | let group = map.get(key); 105 | group.push(str); 106 | } else { 107 | map.set(key, [str]); 108 | } 109 | }); 110 | 111 | return [...map.values()]; 112 | }; 113 | -------------------------------------------------------------------------------- /557__easy__reverse-words-in-a-string-iii.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string} s 3 | * @return {string} 4 | */ 5 | 6 | // use buildin reverse() for array 7 | var reverseWords = function(s) { 8 | s = s.split(" "); 9 | for (let i = 0; i < s.length; i++) { 10 | if (s[i] === "") continue; 11 | 12 | s[i] = s[i] 13 | .split("") 14 | .reverse() 15 | .join(""); 16 | } 17 | return s.join(" "); 18 | }; 19 | 20 | /** 21 | * 22 | * O(n) time 23 | * O(1) space 24 | * 25 | */ 26 | var reverseWords = function(s) { 27 | if (!s || s.length === 0) return s; 28 | let res = ""; 29 | let left = 0; 30 | while (left < s.length) { 31 | if (s[left] === " ") { 32 | res += " "; 33 | left++; 34 | continue; 35 | } 36 | let right = left + 1; 37 | while (right < s.length && s[right] !== " ") { 38 | right++; 39 | } 40 | for (let i = right - 1; i >= left; i--) { 41 | res += s[i]; 42 | } 43 | left = right; 44 | } 45 | return res; 46 | }; 47 | -------------------------------------------------------------------------------- /561__easy__array-partition-i.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1, b1), (a2, b2), ..., (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible. 4 | 5 | Example 1: 6 | Input: [1,4,3,2] 7 | 8 | Output: 4 9 | Explanation: n is 2, and the maximum sum of pairs is 4 = min(1, 2) + min(3, 4). 10 | Note: 11 | n is a positive integer, which is in the range of [1, 10000]. 12 | All the integers in the array will be in the range of [-10000, 10000]. 13 | 14 | */ 15 | 16 | /** 17 | * O(nlogn) time 18 | * O(n) space if merge sort, O(1) if quick sort. 19 | * ALSO NOTE: if use counting sort, time and space will be O(n+k) where k is the range of input 20 | * Runtime: 120 ms, faster than 97.91% of JavaScript 21 | */ 22 | var arrayPairSum = function(nums) { 23 | nums = nums.sort((a, b) => a - b); 24 | let res = 0; 25 | for (let i = 0; i < nums.length; i += 2) { 26 | res += nums[i]; 27 | } 28 | return res; 29 | }; 30 | 31 | /** 32 | * Use bucket sort 33 | * time O(n) 34 | * space O(n) 35 | * Runtime: 76 ms, faster than 100.00% 36 | */ 37 | var arrayPairSum = function(nums) { 38 | let arr = new Array(20001).fill(0); // num range of [-10000, 10000] 39 | let base = 10000; 40 | 41 | for (let i = 0; i < nums.length; i++) { 42 | arr[nums[i] + base]++; 43 | } 44 | 45 | let sum = 0; 46 | let adding = true; 47 | for (let i = 0; i < arr.length; i++) { 48 | while (arr[i] > 0) { 49 | if (adding) sum += i - base; 50 | adding = !adding; 51 | arr[i]--; 52 | } 53 | } 54 | return sum; 55 | }; 56 | -------------------------------------------------------------------------------- /599__easy__minimum-index-sum-of-two-lists.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @param {string[]} list1 3 | * @param {string[]} list2 4 | * @return {string[]} 5 | */ 6 | 7 | /** 8 | * 9 | * O(n) time 10 | * O(n) space 11 | * 12 | * 10m 13 | */ 14 | 15 | var findRestaurant = function(list1, list2) { 16 | let map = {}; 17 | let minIdx = Infinity; 18 | let res = []; 19 | for (let i = 0; i < list1.length; i++) { 20 | map[list1[i]] = i; 21 | } 22 | for (let i = 0; i < list2.length; i++) { 23 | if (map[list2[i]] !== undefined) { 24 | let tmp = map[list2[i]] + i; 25 | if (tmp < minIdx) { 26 | minIdx = tmp; 27 | res = [list2[i]]; 28 | } else if (tmp === minIdx) { 29 | res.push(list2[i]); 30 | } 31 | } 32 | } 33 | return res; 34 | }; 35 | -------------------------------------------------------------------------------- /617__easy__merge-two-binary-trees.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given two binary trees and imagine that when you put one of them to cover the other, some nodes of the two trees are overlapped while the others are not. 4 | 5 | You need to merge them into a new binary tree. The merge rule is that if two nodes overlap, then sum node values up as the new value of the merged node. Otherwise, the NOT null node will be used as the node of new tree. 6 | 7 | Example 1: 8 | 9 | Input: 10 | Tree 1 Tree 2 11 | 1 2 12 | / \ / \ 13 | 3 2 1 3 14 | / \ \ 15 | 5 4 7 16 | Output: 17 | Merged tree: 18 | 3 19 | / \ 20 | 4 5 21 | / \ \ 22 | 5 4 7 23 | 24 | 25 | Note: The merging process must start from the root nodes of both trees. 26 | 27 | */ 28 | 29 | /** 30 | * Definition for a binary tree node. 31 | * function TreeNode(val) { 32 | * this.val = val; 33 | * this.left = this.right = null; 34 | * } 35 | */ 36 | /** 37 | * @param {TreeNode} t1 38 | * @param {TreeNode} t2 39 | * @return {TreeNode} 40 | */ 41 | var mergeTrees = function(t1, t2) { 42 | if (!t1 && !t2) return null; // Both null 43 | if (!t1 || !t2) return t1 || t2; // One node is null 44 | 45 | t1.val += t2.val; 46 | t1.left = mergeTrees(t1.left, t2.left); 47 | t1.right = mergeTrees(t1.right, t2.right); 48 | 49 | return t1; 50 | }; 51 | /** 52 | * Recursive 53 | * 54 | * O(n) time 55 | * O(n) space 56 | * 57 | */ 58 | -------------------------------------------------------------------------------- /652__medium__find-duplicate-subtrees.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given a binary tree, return all duplicate subtrees. For each kind of duplicate subtrees, you only need to return the root node of any one of them. 4 | 5 | Two trees are duplicate if they have the same structure with same node values. 6 | 7 | Example 1: 8 | 9 | 1 10 | / \ 11 | 2 3 12 | / / \ 13 | 4 2 4 14 | / 15 | 4 16 | The following are two duplicate subtrees: 17 | 18 | 2 19 | / 20 | 4 21 | and 22 | 23 | 4 24 | Therefore, you need to return above trees' root in the form of a list. 25 | 26 | */ 27 | 28 | /** 29 | * Definition for a binary tree node. 30 | * function TreeNode(val) { 31 | * this.val = val; 32 | * this.left = this.right = null; 33 | * } 34 | */ 35 | 36 | /** 37 | * @param {TreeNode} root 38 | * @return {TreeNode[]} 39 | */ 40 | var findDuplicateSubtrees = function(root) { 41 | const map = new Map(); 42 | const res = []; 43 | preOrder(root); 44 | return res; 45 | 46 | function preOrder(root) { 47 | if (root === null) return "#"; 48 | 49 | let key = root.val + "|" + preOrder(root.left) + "|" + preOrder(root.right); 50 | map.set(key, (map.get(key) || 0) + 1); 51 | 52 | if (map.get(key) === 2) { 53 | res.push(root); 54 | } 55 | 56 | return key; 57 | } 58 | }; 59 | /** 60 | * 61 | * O(n) time 62 | * O(n) space 63 | * 64 | * 30m 65 | */ 66 | -------------------------------------------------------------------------------- /705__easy__design-hashset.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | create 1000 bucket, use linked list inside, because linked list delete and add are O(1) 4 | 5 | 1. Swap 6 | 7 | There is a tricky strategy we can use. 8 | First, swap the element which we want to remove with the last element in the bucket. 9 | Then remove the last element. By this way, we successfully remove the element in O(1) time complexity. 10 | 11 | 2. Linked List 12 | 13 | Another way to achieve this goal is to use a linked list instead of an array list. 14 | By this way, we can remove the element in O(1) time complexity without modifying the order in the list. 15 | 16 | 17 | The Principle of Built-in Hash Table 18 | The typical design of built-in hash table is: 19 | 20 | The key value can be any hashable type. And a value which belongs to a hashable type will have a hashcode. 21 | This code will be used in the mapping function to get the bucket index. 22 | Each bucket contains an array to store all the values in the same bucket initially. 23 | If there are too many values in the same bucket, these values will be maintained in a height-balanced binary search tree instead. 24 | The average time complexity of both insertion and search is still O(1). 25 | And the time complexity in the worst case is O(logN) for both insertion and search by using height-balanced BST. 26 | It is a trade-off between insertion and search. 27 | 28 | */ 29 | 30 | /** 31 | * Initialize your data structure here. 32 | */ 33 | var MyHashSet = function() { 34 | this.map = new Array(1000); 35 | this.hash = function(key) { 36 | return key % 1000; 37 | }; 38 | }; 39 | 40 | /** 41 | * @param {number} key 42 | * @return {void} 43 | */ 44 | MyHashSet.prototype.add = function(key) { 45 | let bucket = this.hash(key); 46 | this.map[bucket] = this.map[bucket] || []; 47 | if (!this.map[bucket].includes(key)) this.map[bucket].push(key); 48 | }; 49 | 50 | /** 51 | * @param {number} key 52 | * @return {void} 53 | */ 54 | MyHashSet.prototype.remove = function(key) { 55 | let bucket = this.hash(key); 56 | this.map[bucket] = this.map[bucket] || []; 57 | let index = this.map[bucket].indexOf(key); 58 | if (index > -1) this.map[bucket].splice(index, 1); 59 | }; 60 | 61 | /** 62 | * Returns true if this set contains the specified element 63 | * @param {number} key 64 | * @return {boolean} 65 | */ 66 | MyHashSet.prototype.contains = function(key) { 67 | let bucket = this.hash(key); 68 | this.map[bucket] = this.map[bucket] || []; 69 | return this.map[bucket].includes(key); 70 | }; 71 | 72 | /** 73 | * Your MyHashSet object will be instantiated and called as such: 74 | * var obj = Object.create(MyHashSet).createNew() 75 | * obj.add(key) 76 | * obj.remove(key) 77 | * var param_3 = obj.contains(key) 78 | */ 79 | -------------------------------------------------------------------------------- /706__easy__design-hashmap.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Initialize your data structure here. 3 | */ 4 | /* 5 | 6 | create 1000 bucket, use linked list inside, because linked list delete and add are O(1) 7 | 8 | 1. Swap 9 | 10 | There is a tricky strategy we can use. 11 | First, swap the element which we want to remove with the last element in the bucket. 12 | Then remove the last element. By this way, we successfully remove the element in O(1) time complexity. 13 | 14 | 2. Linked List 15 | 16 | Another way to achieve this goal is to use a linked list instead of an array list. 17 | By this way, we can remove the element in O(1) time complexity without modifying the order in the list. 18 | 19 | 20 | The Principle of Built-in Hash Table 21 | The typical design of built-in hash table is: 22 | 23 | The key value can be any hashable type. And a value which belongs to a hashable type will have a hashcode. 24 | This code will be used in the mapping function to get the bucket index. 25 | Each bucket contains an array to store all the values in the same bucket initially. 26 | If there are too many values in the same bucket, these values will be maintained in a height-balanced binary search tree instead. 27 | The average time complexity of both insertion and search is still O(1). 28 | And the time complexity in the worst case is O(logN) for both insertion and search by using height-balanced BST. 29 | It is a trade-off between insertion and search. 30 | 31 | */ 32 | var MyHashMap = function() { 33 | this.map = {}; 34 | }; 35 | 36 | /** 37 | * value will always be non-negative. 38 | * @param {number} key 39 | * @param {number} value 40 | * @return {void} 41 | */ 42 | MyHashMap.prototype.put = function(key, value) { 43 | this.map[key] = value; 44 | }; 45 | 46 | /** 47 | * Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key 48 | * @param {number} key 49 | * @return {number} 50 | */ 51 | MyHashMap.prototype.get = function(key) { 52 | return this.map[key] !== undefined ? this.map[key] : -1; 53 | }; 54 | 55 | /** 56 | * Removes the mapping of the specified value key if this map contains a mapping for the key 57 | * @param {number} key 58 | * @return {void} 59 | */ 60 | MyHashMap.prototype.remove = function(key) { 61 | delete this.map[key]; 62 | }; 63 | 64 | /** 65 | * Your MyHashMap object will be instantiated and called as such: 66 | * var obj = Object.create(MyHashMap).createNew() 67 | * obj.put(key,value) 68 | * var param_2 = obj.get(key) 69 | * obj.remove(key) 70 | */ 71 | -------------------------------------------------------------------------------- /709__easy__to-lower-case.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Implement function ToLowerCase() that has a string parameter str, and returns the same string in lowercase. 4 | 5 | Example 1: 6 | 7 | Input: "Hello" 8 | Output: "hello" 9 | Example 2: 10 | 11 | Input: "here" 12 | Output: "here" 13 | Example 3: 14 | 15 | Input: "LOVELY" 16 | Output: "lovely" 17 | 18 | */ 19 | 20 | /** 21 | * 22 | * O(n) time 23 | * O(n) space 24 | * Runtime: 48 ms, faster than 100.00% 25 | */ 26 | /** 27 | * @param {string} str 28 | * @return {string} 29 | */ 30 | var toLowerCase = function(str) { 31 | if (!str) return str; 32 | // Char Code A-Z => 65 - 90, a-z 97 - 122 33 | // A -> a need + 32 to char code of A 34 | let res = ""; 35 | for (let i = 0; i < str.length; i++) { 36 | let cCode = str[i].charCodeAt(0); 37 | if (65 <= cCode && cCode <= 90) { 38 | res += String.fromCharCode(cCode + 32); 39 | } else { 40 | res += str[i]; 41 | } 42 | } 43 | return res; 44 | }; 45 | -------------------------------------------------------------------------------- /760__easy__find-anagram-mappings.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Given two lists Aand B, and B is an anagram of A. B is an anagram of A means B is made by randomizing the order of the elements in A. 4 | 5 | We want to find an index mapping P, from A to B. A mapping P[i] = j means the ith element in A appears in B at index j. 6 | 7 | These lists A and B may contain duplicates. If there are multiple answers, output any of them. 8 | 9 | For example, given 10 | 11 | A = [12, 28, 46, 32, 50] 12 | B = [50, 12, 32, 46, 28] 13 | We should return 14 | [1, 4, 3, 2, 0] 15 | as P[0] = 1 because the 0th element of A appears at B[1], and P[1] = 4 because the 1st element of A appears at B[4], and so on. 16 | Note: 17 | 18 | A, B have equal lengths in range [1, 100]. 19 | A[i], B[i] are integers in range [0, 10^5] 20 | 21 | */ 22 | /** 23 | * 24 | * O(n) time 25 | * O(n) space 26 | * 27 | * Runtime: 52 ms, faster than 100.00% 28 | */ 29 | /** 30 | * @param {number[]} A 31 | * @param {number[]} B 32 | * @return {number[]} 33 | */ 34 | var anagramMappings = function(A, B) { 35 | if (!A || !B) return null; 36 | 37 | let map = {}; // {} is faster than Map() 38 | for (let i = 0; i < B.length; i++) { 39 | if (!map[B[i]]) map[B[i]] = i; 40 | } 41 | 42 | let res = new Array(A.length); 43 | for (let i = 0; i < A.length; i++) { 44 | res[i] = map[A[i]]; 45 | } 46 | 47 | return res; 48 | }; 49 | -------------------------------------------------------------------------------- /771__easy__jewels-and-stones.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | You're given strings J representing the types of stones that are jewels, and S representing the stones you have. Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels. 4 | 5 | The letters in J are guaranteed distinct, and all characters in J and S are letters. Letters are case sensitive, so "a" is considered a different type of stone from "A". 6 | 7 | Example 1: 8 | 9 | Input: J = "aA", S = "aAAbbbb" 10 | Output: 3 11 | Example 2: 12 | 13 | Input: J = "z", S = "ZZ" 14 | Output: 0 15 | Note: 16 | 17 | S and J will consist of letters and have length at most 50. 18 | The characters in J are distinct. 19 | 20 | */ 21 | 22 | /** 23 | * @param {string} J 24 | * @param {string} S 25 | * @return {number} 26 | */ 27 | var numJewelsInStones = function(J, S) { 28 | if (!J || !S) return 0; 29 | 30 | let count = 0; 31 | let set = new Set(); 32 | 33 | for (let i = 0; i < J.length; i++) { 34 | set.add(J[i]); 35 | } 36 | for (let i = 0; i < S.length; i++) { 37 | if (set.has(S[i])) count++; 38 | } 39 | return count; 40 | }; 41 | /** 42 | * 43 | * O(J.length + S.length) time 44 | * O(J.length) space 45 | * 46 | * 3m 47 | */ 48 | -------------------------------------------------------------------------------- /852__easy__peak-index-in-a-mountain-array.js: -------------------------------------------------------------------------------- 1 | /** 2 | 3 | Let's call an array A a mountain if the following properties hold: 4 | 5 | A.length >= 3 6 | There exists some 0 < i < A.length - 1 such that A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1] 7 | Given an array that is definitely a mountain, return any i such that A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1]. 8 | 9 | Example 1: 10 | 11 | Input: [0,1,0] 12 | Output: 1 13 | Example 2: 14 | 15 | Input: [0,2,1,0] 16 | Output: 1 17 | Note: 18 | 19 | 3 <= A.length <= 10000 20 | 0 <= A[i] <= 10^6 21 | A is a mountain, as defined above. 22 | 23 | */ 24 | 25 | /** 26 | * Binary search 27 | * O(n) time 28 | * O(1) space 29 | * 30 | * 20m 31 | */ 32 | var peakIndexInMountainArray = function(A) { 33 | let left = 0; 34 | let right = A.length - 1; 35 | let curr = ~~(A.length / 2); 36 | 37 | while (left < right) { 38 | if (A[curr - 1] < A[curr] && A[curr] > A[curr + 1]) { 39 | // low < high > low, peak found! 40 | return curr; 41 | } else if (A[curr - 1] < A[curr] && A[curr] < A[curr + 1]) { 42 | // ex: 5 - 6 - 7, up-trend so peak at right hand side 43 | left = curr; 44 | curr = ~~((left + right) / 2); 45 | } else { 46 | right = curr; 47 | curr = ~~((left + right) / 2); 48 | } 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /922__easy__sort-array-by-parity-ii.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Given an array A of non-negative integers, half of the integers in A are odd, and half of the integers are even. 4 | 5 | Sort the array so that whenever A[i] is odd, i is odd; and whenever A[i] is even, i is even. 6 | 7 | You may return any answer array that satisfies this condition. 8 | 9 | 10 | Example 1: 11 | 12 | Input: [4,2,5,7] 13 | Output: [4,5,2,7] 14 | Explanation: [4,7,2,5], [2,5,4,7], [2,7,4,5] would also have been accepted. 15 | 16 | 17 | Note: 18 | 19 | 2 <= A.length <= 20000 20 | A.length % 2 == 0 21 | 0 <= A[i] <= 1000 22 | 23 | */ 24 | 25 | /** 26 | * check even and odd index until both not satisfies the condition then swap them (in place swap) 27 | * time O(n) 28 | * space O(1) 29 | * Runtime: 104 ms, faster than 85.27% of JavaScript 30 | */ 31 | var sortArrayByParityII = function(A) { 32 | let n = A.length; 33 | let evenIdx = 0; 34 | let oddIdx = 1; 35 | 36 | while (evenIdx < n && oddIdx < n) { 37 | while (evenIdx < n && A[evenIdx] % 2 == 0) { 38 | evenIdx += 2; 39 | } 40 | while (oddIdx < n && A[oddIdx] % 2 != 0) { 41 | oddIdx += 2; 42 | } 43 | if (evenIdx < n && oddIdx < n) { 44 | [A[evenIdx], A[oddIdx]] = [A[oddIdx], A[evenIdx]]; 45 | evenIdx += 2; 46 | oddIdx += 2; 47 | } 48 | } 49 | 50 | return A; 51 | }; 52 | -------------------------------------------------------------------------------- /Algorithm Implementation/QuickSort.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | ✅ Like Merge Sort, QuickSort is a Divide and Conquer algorithm. 4 | 5 | It picks an element as pivot and partitions the given array around the picked pivot. 6 | There are many different versions of quickSort that pick pivot in different ways. 7 | 8 | 1. Always pick first element as pivot. 9 | 2. Always pick last element as pivot (implemented below) 10 | 3. Pick a random element as pivot. 11 | 4. Pick median as pivot. 12 | 13 | The key process in quickSort is partition(). Target of partitions is, 14 | given an array and an element x of array as pivot, put x at its correct 15 | position in sorted array and put all smaller elements (smaller than x) before x, 16 | and put all greater elements (greater than x) after x. All this should be done in linear time. 17 | 18 | */ 19 | 20 | function quickSort (arr, low, high) { 21 | if (low < high) { 22 | let p = partition(arr, low, high) 23 | 24 | quickSort(arr, low, p - 1); // Before pi 25 | quickSort(arr, p + 1, high); // After pi 26 | } 27 | } 28 | /* 29 | This function takes last element as pivot, places 30 | the pivot element at its correct position in sorted 31 | array, and places all smaller (smaller than pivot) 32 | to left of pivot and all greater elements to right 33 | of pivot 34 | 35 | 5 6 1 2 4 9 36 | * 37 | 38 | */ 39 | function quickSort (arr, low, high) { 40 | let idx = partition(arr, low, high); 41 | 42 | if (low < idx - 1) { 43 | quickSort(arr, low, idx - 1); // Before pi 44 | } 45 | 46 | if (high > idx) { 47 | quickSort(arr, idx, high); // After pi 48 | } 49 | 50 | } 51 | 52 | function partition (arr, low, high) { 53 | let pindex = low; 54 | 55 | while (low <= high) { 56 | // from left find 57 | while (arr[low] < arr[pindex]) { 58 | low++; 59 | } 60 | while (arr[pindex] < arr[high]) { 61 | high--; 62 | } 63 | if (low <= high) { 64 | [arr[low], arr[high]] = [arr[high], arr[low]]; 65 | low++; 66 | high--; 67 | } 68 | } 69 | return low; 70 | } 71 | 72 | // TEST 73 | let a = [3, 5, 1, 7, 8, 9, 4, 2, 6, 10]; 74 | console.log(a); 75 | quickSort(a, 0, a.length - 1); 76 | console.log(a); 77 | -------------------------------------------------------------------------------- /Others/debounce.js: -------------------------------------------------------------------------------- 1 | 2 | function sayHello () { 3 | console.log('Hello, World'); 4 | } 5 | 6 | 7 | function debounce (func, wait, immediate) { 8 | let timeout; 9 | 10 | return function () { 11 | let context = this; 12 | let args = arguments; 13 | let callNow = immediate && !timeout; 14 | 15 | clearTimeout(timeout); 16 | 17 | timeout = setTimeout(function () { 18 | timeout = null; 19 | if (!immediate) { 20 | func.apply(context, args); 21 | } 22 | }, wait); 23 | 24 | if (callNow) func.apply(context, args) 25 | } 26 | } 27 | 28 | var callDebounce = debounce(sayHello, 1500, true); 29 | -------------------------------------------------------------------------------- /Python3/000__easy__temp.py: -------------------------------------------------------------------------------- 1 | """ 2 | @param 3 | 4 | @return 5 | 6 | """ 7 | 8 | """ 9 | O(n) time 10 | O(1) space 11 | 12 | 10m 13 | """ 14 | -------------------------------------------------------------------------------- /Python3/680__easy__valid-palindrome-ii.py: -------------------------------------------------------------------------------- 1 | """ 2 | Given a non-empty string s, you may delete at most one character. Judge whether you can make it a palindrome. 3 | 4 | Example 1: 5 | Input: "aba" 6 | Output: True 7 | 8 | Example 2: 9 | Input: "abca" 10 | Output: True 11 | Explanation: You could delete the character 'c'. 12 | 13 | Note: 14 | The string will only contain lowercase characters a-z. The maximum length of the string is 50000. 15 | """ 16 | 17 | 18 | class Solution: 19 | """ 20 | O(n) time 21 | O(1) space 22 | 30m 23 | 24 | Runtime: 188 ms, faster than 46.44% 25 | """ 26 | 27 | def validPalindrome(self, s): 28 | """ 29 | :type s: str 30 | :rtype: bool 31 | """ 32 | def isPal(lo, hi, canSkip): 33 | while lo < hi: 34 | if s[lo] != s[hi]: 35 | if not canSkip: 36 | return False 37 | return isPal(lo+1, hi, False) or isPal(lo, hi-1, False) 38 | lo += 1 39 | hi -= 1 40 | return True 41 | 42 | return isPal(0, len(s)-1, True) 43 | 44 | 45 | class Solution2: 46 | """ 47 | O(n) time 48 | O(n) space 49 | 30m 50 | 51 | Runtime: 72 ms, faster than 99.89% 52 | """ 53 | 54 | def validPalindrome(self, s): 55 | """ 56 | :type s: str 57 | :rtype: bool 58 | """ 59 | r = s[::-1] 60 | if s == r: 61 | return True 62 | 63 | for idx in range(len(s)): 64 | if s[idx] != r[idx]: 65 | break 66 | 67 | # skip by 1 will cover the case of two possible delete 68 | for k in idx, len(s)-idx-1: 69 | x = s[:k]+s[k+1:] 70 | if x == x[::-1]: 71 | return True 72 | 73 | return False 74 | 75 | 76 | class Solution3: 77 | """ 78 | O(n) time 79 | O(n) space 80 | 30m 81 | 82 | Runtime: 84 ms, faster than 95.76% 83 | """ 84 | 85 | def validPalindrome(self, s): 86 | """ 87 | :type s: str 88 | :rtype: bool 89 | """ 90 | r = s[::-1] 91 | if s == r: 92 | return True 93 | 94 | idx = 0 95 | while idx < len(s): 96 | if s[idx] != r[idx]: 97 | break 98 | idx += 1 99 | 100 | # skip by 1 will cover the case of two possible delete 101 | for k in idx, len(s)-idx-1: 102 | x = s[:k]+s[k+1:] 103 | if x == x[::-1]: 104 | return True 105 | 106 | return False 107 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | Just for fun? 🤣🤣🤣 4 | 5 | Coding problem source: https://leetcode.com/problemset/all/ 6 | -------------------------------------------------------------------------------- /Typescript/121__easy_Best Time to Buy and Sell Stock.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 121. Best Time to Buy and Sell Stock 4 | Easy 5 | 28.9K 6 | 983 7 | Companies 8 | You are given an array prices where prices[i] is the price of a given stock on the ith day. 9 | 10 | You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock. 11 | 12 | Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return 0. 13 | 14 | 15 | 16 | Example 1: 17 | 18 | Input: prices = [7,1,5,3,6,4] 19 | Output: 5 20 | Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. 21 | Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell. 22 | Example 2: 23 | 24 | Input: prices = [7,6,4,3,1] 25 | Output: 0 26 | Explanation: In this case, no transactions are done and the max profit = 0. 27 | 28 | 29 | Constraints: 30 | 31 | 1 <= prices.length <= 105 32 | 0 <= prices[i] <= 104 33 | Accepted 34 | 3.9M 35 | Submissions 36 | 7.3M 37 | Acceptance Rate 38 | 53.5% 39 | 40 | */ 41 | function maxProfit(prices: number[]): number { 42 | if (!prices) return 43 | // 1. find min 44 | // find low point 45 | let minBuy = prices[0] 46 | let maxProfit = 0 47 | for (let i = 1; i < prices.length; i++) { 48 | maxProfit = Math.max(maxProfit, prices[i] - minBuy) 49 | minBuy = Math.min(minBuy, prices[i]) 50 | } 51 | return maxProfit 52 | } 53 | -------------------------------------------------------------------------------- /Typescript/125__easy_Valid Palindrome.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 125. Valid Palindrome 3 | Easy 4 | 8.4K 5 | 8K 6 | Companies 7 | A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers. 8 | 9 | Given a string s, return true if it is a palindrome, or false otherwise. 10 | 11 | 12 | 13 | Example 1: 14 | 15 | Input: s = "A man, a plan, a canal: Panama" 16 | Output: true 17 | Explanation: "amanaplanacanalpanama" is a palindrome. 18 | Example 2: 19 | 20 | Input: s = "race a car" 21 | Output: false 22 | Explanation: "raceacar" is not a palindrome. 23 | Example 3: 24 | 25 | Input: s = " " 26 | Output: true 27 | Explanation: s is an empty string "" after removing non-alphanumeric characters. 28 | Since an empty string reads the same forward and backward, it is a palindrome. 29 | 30 | 31 | Constraints: 32 | 33 | 1 <= s.length <= 2 * 105 34 | s consists only of printable ASCII characters. 35 | Accepted 36 | 2.4M 37 | Submissions 38 | 5.2M 39 | Acceptance Rate 40 | 45.9% 41 | */ 42 | 43 | function isPalindrome(s: string): boolean { 44 | if (!s) return false 45 | 46 | const isLetterOrNum = (char) => { 47 | return /^[A-Za-z0-9]*$/.test(char) 48 | } 49 | 50 | let l = 0, 51 | r = s.length - 1 52 | while (l < r) { 53 | while (!isLetterOrNum(s[l])) l++ 54 | while (!isLetterOrNum(s[r])) r-- 55 | if (l < r && s[l].toLowerCase() !== s[r].toLowerCase()) return false 56 | l++ 57 | r-- 58 | } 59 | return true 60 | } 61 | -------------------------------------------------------------------------------- /Typescript/169__easy_Majority Element.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 169. Majority Element 4 | Easy 5 | 17.3K 6 | 514 7 | Companies 8 | Given an array nums of size n, return the majority element. 9 | 10 | The majority element is the element that appears more than ⌊n / 2⌋ times. You may assume that the majority element always exists in the array. 11 | 12 | 13 | 14 | Example 1: 15 | 16 | Input: nums = [3,2,3] 17 | Output: 3 18 | Example 2: 19 | 20 | Input: nums = [2,2,1,1,1,2,2] 21 | Output: 2 22 | 23 | 24 | Constraints: 25 | 26 | n == nums.length 27 | 1 <= n <= 5 * 104 28 | -109 <= nums[i] <= 109 29 | 30 | 31 | Follow-up: Could you solve the problem in linear time and in O(1) space? 32 | 33 | */ 34 | function majorityElement(nums: number[]): number { 35 | // [3,2,3] 36 | // ^ 37 | let count = 0 38 | let candidate: number | null = null 39 | for (let i = 0; i < nums.length; i++) { 40 | if (count === 0) candidate = nums[i] 41 | count += candidate === nums[i] ? 1 : -1 42 | } 43 | return candidate ?? 0 44 | } 45 | -------------------------------------------------------------------------------- /Typescript/189__Medium_Rotate Array.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 189. Rotate Array 4 | Medium 5 | 16.5K 6 | 1.8K 7 | Companies 8 | Given an integer array nums, rotate the array to the right by k steps, where k is non-negative. 9 | 10 | 11 | 12 | Example 1: 13 | 14 | Input: nums = [1,2,3,4,5,6,7], k = 3 15 | Output: [5,6,7,1,2,3,4] 16 | Explanation: 17 | rotate 1 steps to the right: [7,1,2,3,4,5,6] 18 | rotate 2 steps to the right: [6,7,1,2,3,4,5] 19 | rotate 3 steps to the right: [5,6,7,1,2,3,4] 20 | Example 2: 21 | 22 | Input: nums = [-1,-100,3,99], k = 2 23 | Output: [3,99,-1,-100] 24 | Explanation: 25 | rotate 1 steps to the right: [99,-1,-100,3] 26 | rotate 2 steps to the right: [3,99,-1,-100] 27 | 28 | 29 | Constraints: 30 | 31 | 1 <= nums.length <= 105 32 | -231 <= nums[i] <= 231 - 1 33 | 0 <= k <= 105 34 | 35 | 36 | Follow up: 37 | 38 | Try to come up with as many solutions as you can. There are at least three different ways to solve this problem. 39 | Could you do it in-place with O(1) extra space? 40 | Accepted 41 | 1.8M 42 | Submissions 43 | 4.5M 44 | Acceptance Rate 45 | 39.9% 46 | */ 47 | 48 | /** 49 | Do not return anything, modify nums in-place instead. 50 | */ 51 | function rotate(nums: number[], k: number): void { 52 | // [1,2,3,4,5,6,7] 53 | // [5,6,7,1,2,3,4] 54 | //[5,6,7,1,2,3,4] 55 | if (nums.length === 0 || k % nums.length === 0) return 56 | 57 | k = k % nums.length // normalize so it is less than nums length 58 | let count = 0 59 | for (let startIdx = 0; count < nums.length; startIdx++) { 60 | let currIdx = startIdx 61 | let numHolder = nums[startIdx] 62 | do { 63 | let nextIdx = (currIdx + k) % nums.length 64 | let temp = nums[nextIdx] 65 | nums[nextIdx] = numHolder 66 | numHolder = temp 67 | 68 | count++ 69 | currIdx = nextIdx 70 | } while (startIdx !== currIdx) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /Typescript/1__easy_Two Sum.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 1. Two Sum 4 | Easy 5 | 52.6K 6 | 1.7K 7 | Companies 8 | Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target. 9 | 10 | You may assume that each input would have exactly one solution, and you may not use the same element twice. 11 | 12 | You can return the answer in any order. 13 | 14 | 15 | 16 | Example 1: 17 | 18 | Input: nums = [2,7,11,15], target = 9 19 | Output: [0,1] 20 | Explanation: Because nums[0] + nums[1] == 9, we return [0, 1]. 21 | Example 2: 22 | 23 | Input: nums = [3,2,4], target = 6 24 | Output: [1,2] 25 | Example 3: 26 | 27 | Input: nums = [3,3], target = 6 28 | Output: [0,1] 29 | 30 | 31 | Constraints: 32 | 33 | 2 <= nums.length <= 104 34 | -109 <= nums[i] <= 109 35 | -109 <= target <= 109 36 | Only one valid answer exists. 37 | 38 | 39 | Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity? 40 | Accepted 41 | 11.2M 42 | Submissions 43 | 22M 44 | Acceptance Rate 45 | 50.9% 46 | 47 | */ 48 | 49 | export function twoSum(nums: number[], target: number): number[] | undefined { 50 | if (nums === undefined || target === undefined) return [] 51 | 52 | let map = new Map() 53 | 54 | for (let i = 0; i < nums.length; i++) { 55 | if (map.has(nums[i])) return [map.get(nums[i])!, i] 56 | map.set(target - nums[i], i) 57 | } 58 | return [] 59 | 60 | // for (let i = 0; i < nums.length; i++) { 61 | // let complement = target - nums[i] 62 | // if (map.get(complement) !== undefined) return [map.get(complement), i] 63 | // map.set(nums[i], i) 64 | // } 65 | } 66 | -------------------------------------------------------------------------------- /Typescript/205__easy_Isomorphic Strings.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 205. Isomorphic Strings 4 | Easy 5 | 7.8K 6 | 1.7K 7 | Companies 8 | Given two strings s and t, determine if they are isomorphic. 9 | 10 | Two strings s and t are isomorphic if the characters in s can be replaced to get t. 11 | 12 | All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character, but a character may map to itself. 13 | 14 | 15 | 16 | Example 1: 17 | 18 | Input: s = "egg", t = "add" 19 | Output: true 20 | Example 2: 21 | 22 | Input: s = "foo", t = "bar" 23 | Output: false 24 | Example 3: 25 | 26 | Input: s = "paper", t = "title" 27 | Output: true 28 | 29 | 30 | Constraints: 31 | 32 | 1 <= s.length <= 5 * 104 33 | t.length == s.length 34 | s and t consist of any valid ascii character. 35 | Accepted 36 | 1M 37 | Submissions 38 | 2.4M 39 | Acceptance Rate 40 | 43.5% 41 | 42 | */ 43 | 44 | function isIsomorphic(s: string, t: string): boolean { 45 | if (!s || !t || s.length !== t.length) return false 46 | // index and reverse index 47 | const mapS = new Map() 48 | const mapT = new Map() 49 | for (let i = 0; i < s.length; i++) { 50 | if (s[i] === s[t]) continue 51 | if ( 52 | (mapS.has(s[i]) && mapS.get(s[i]) !== t[i]) || 53 | (mapT.has(t[i]) && mapT.get(t[i]) !== s[i]) 54 | ) 55 | return false 56 | mapS.set(s[i], t[i]) 57 | mapT.set(t[i], s[i]) 58 | } 59 | return true 60 | } 61 | -------------------------------------------------------------------------------- /Typescript/242__easy_Valid Anagram.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 242. Valid Anagram 4 | Easy 5 | 10.9K 6 | 341 7 | Companies 8 | Given two strings s and t, return true if t is an anagram of s, and false otherwise. 9 | 10 | An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once. 11 | 12 | 13 | 14 | Example 1: 15 | 16 | Input: s = "anagram", t = "nagaram" 17 | Output: true 18 | Example 2: 19 | 20 | Input: s = "rat", t = "car" 21 | Output: false 22 | 23 | 24 | Constraints: 25 | 26 | 1 <= s.length, t.length <= 5 * 104 27 | s and t consist of lowercase English letters. 28 | 29 | 30 | Follow up: What if the inputs contain Unicode characters? How would you adapt your solution to such a case? 31 | 32 | Accepted 33 | 2.7M 34 | Submissions 35 | 4.3M 36 | Acceptance Rate 37 | 63.4% 38 | */ 39 | 40 | function isAnagram(s: string, t: string): boolean { 41 | if (!s || !t || s.length !== t.length) return false 42 | 43 | const map = new Map() 44 | for (let i = 0; i < s.length; i++) { 45 | map.set(s[i], 1 + (map.get(s[i]) ?? 0)) 46 | } 47 | for (let i = 0; i < s.length; i++) { 48 | if (!map.has(t[i]) || map.get(t[i]) <= 0) return false 49 | map.set(t[i], map.get(t[i]) - 1) 50 | } 51 | return true 52 | } 53 | -------------------------------------------------------------------------------- /Typescript/26__easy_Remove Duplicates from Sorted Array.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 26. Remove Duplicates from Sorted Array 3 | Easy 4 | 12.9K 5 | 17.1K 6 | Companies 7 | Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same. Then return the number of unique elements in nums. 8 | 9 | Consider the number of unique elements of nums to be k, to get accepted, you need to do the following things: 10 | 11 | Change the array nums such that the first k elements of nums contain the unique elements in the order they were present in nums initially. The remaining elements of nums are not important as well as the size of nums. 12 | Return k. 13 | Custom Judge: 14 | 15 | The judge will test your solution with the following code: 16 | 17 | int[] nums = [...]; // Input array 18 | int[] expectedNums = [...]; // The expected answer with correct length 19 | 20 | int k = removeDuplicates(nums); // Calls your implementation 21 | 22 | assert k == expectedNums.length; 23 | for (int i = 0; i < k; i++) { 24 | assert nums[i] == expectedNums[i]; 25 | } 26 | If all assertions pass, then your solution will be accepted. 27 | 28 | 29 | 30 | Example 1: 31 | 32 | Input: nums = [1,1,2] 33 | Output: 2, nums = [1,2,_] 34 | Explanation: Your function should return k = 2, with the first two elements of nums being 1 and 2 respectively. 35 | It does not matter what you leave beyond the returned k (hence they are underscores). 36 | Example 2: 37 | 38 | Input: nums = [0,0,1,1,1,2,2,3,3,4] 39 | Output: 5, nums = [0,1,2,3,4,_,_,_,_,_] 40 | Explanation: Your function should return k = 5, with the first five elements of nums being 0, 1, 2, 3, and 4 respectively. 41 | It does not matter what you leave beyond the returned k (hence they are underscores). 42 | 43 | 44 | Constraints: 45 | 46 | 1 <= nums.length <= 3 * 104 47 | -100 <= nums[i] <= 100 48 | nums is sorted in non-decreasing order. 49 | */ 50 | function removeDuplicates(nums: number[]): number { 51 | // [0,0,1,1,1,2,2,3,3,4] 52 | // ^ 53 | // [0,0,1,1,1,2,2,3,3,4] 54 | let start = 0 55 | for (let i = 0; i < nums.length; i++) { 56 | if (nums[start] !== nums[i]) { 57 | start++ 58 | nums[start] = nums[i] 59 | } 60 | } 61 | return start + 1 62 | } 63 | -------------------------------------------------------------------------------- /Typescript/27__easy_Remove Element.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 27. Remove Element 4 | Easy 5 | 1.4K 6 | 2K 7 | Companies 8 | Given an integer array nums and an integer val, remove all occurrences of val in nums in-place. The order of the elements may be changed. Then return the number of elements in nums which are not equal to val. 9 | 10 | Consider the number of elements in nums which are not equal to val be k, to get accepted, you need to do the following things: 11 | 12 | Change the array nums such that the first k elements of nums contain the elements which are not equal to val. The remaining elements of nums are not important as well as the size of nums. 13 | Return k. 14 | Custom Judge: 15 | 16 | The judge will test your solution with the following code: 17 | 18 | int[] nums = [...]; // Input array 19 | int val = ...; // Value to remove 20 | int[] expectedNums = [...]; // The expected answer with correct length. 21 | // It is sorted with no values equaling val. 22 | 23 | int k = removeElement(nums, val); // Calls your implementation 24 | 25 | assert k == expectedNums.length; 26 | sort(nums, 0, k); // Sort the first k elements of nums 27 | for (int i = 0; i < actualLength; i++) { 28 | assert nums[i] == expectedNums[i]; 29 | } 30 | If all assertions pass, then your solution will be accepted. 31 | 32 | 33 | 34 | Example 1: 35 | 36 | Input: nums = [3,2,2,3], val = 3 37 | Output: 2, nums = [2,2,_,_] 38 | Explanation: Your function should return k = 2, with the first two elements of nums being 2. 39 | It does not matter what you leave beyond the returned k (hence they are underscores). 40 | Example 2: 41 | 42 | Input: nums = [0,1,2,2,3,0,4,2], val = 2 43 | Output: 5, nums = [0,1,4,0,3,_,_,_] 44 | Explanation: Your function should return k = 5, with the first five elements of nums containing 0, 0, 1, 3, and 4. 45 | Note that the five elements can be returned in any order. 46 | It does not matter what you leave beyond the returned k (hence they are underscores). 47 | 48 | 49 | Constraints: 50 | 51 | 0 <= nums.length <= 100 52 | 0 <= nums[i] <= 50 53 | 0 <= val <= 100 54 | 55 | */ 56 | 57 | function removeElement(nums: number[], val: number): number { 58 | // [3,3,2,3] val = 3 59 | // ^ 60 | // 61 | let start = 0 62 | for (let i = 0; i < nums.length; i++) { 63 | if (nums[i] !== val) { 64 | nums[start] = nums[i] 65 | start++ 66 | } 67 | } 68 | return start 69 | } 70 | -------------------------------------------------------------------------------- /Typescript/383__easy_Ransom Note.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 383. Ransom Note 4 | Easy 5 | 4.6K 6 | 464 7 | Companies 8 | Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise. 9 | 10 | Each letter in magazine can only be used once in ransomNote. 11 | 12 | 13 | 14 | Example 1: 15 | 16 | Input: ransomNote = "a", magazine = "b" 17 | Output: false 18 | Example 2: 19 | 20 | Input: ransomNote = "aa", magazine = "ab" 21 | Output: false 22 | Example 3: 23 | 24 | Input: ransomNote = "aa", magazine = "aab" 25 | Output: true 26 | 27 | 28 | Constraints: 29 | 30 | 1 <= ransomNote.length, magazine.length <= 105 31 | ransomNote and magazine consist of lowercase English letters. 32 | Accepted 33 | 933.6K 34 | Submissions 35 | 1.6M 36 | Acceptance Rate 37 | 59.8% 38 | */ 39 | 40 | function canConstruct(ransomNote: string, magazine: string): boolean { 41 | if (!ransomNote || !magazine) return false 42 | 43 | let map = new Map() 44 | for (let i = 0; i < magazine.length; i++) { 45 | map.set(magazine[i], map.has(magazine[i]) ? map.get(magazine[i]) + 1 : 1) 46 | } 47 | for (let i = 0; i < ransomNote.length; i++) { 48 | let curr = ransomNote[i] 49 | if (!map.has(curr) || map.get(curr) === 0) return false 50 | map.set(curr, map.get(curr) - 1) 51 | } 52 | return true 53 | } 54 | -------------------------------------------------------------------------------- /Typescript/392__easy_Is Subsequence.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 392. Is Subsequence 4 | Easy 5 | 9K 6 | 478 7 | Companies 8 | Given two strings s and t, return true if s is a subsequence of t, or false otherwise. 9 | 10 | A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e., "ace" is a subsequence of "abcde" while "aec" is not). 11 | 12 | 13 | 14 | Example 1: 15 | 16 | Input: s = "abc", t = "ahbgdc" 17 | Output: true 18 | Example 2: 19 | 20 | Input: s = "axc", t = "ahbgdc" 21 | Output: false 22 | 23 | 24 | Constraints: 25 | 26 | 0 <= s.length <= 100 27 | 0 <= t.length <= 104 28 | s and t consist only of lowercase English letters. 29 | 30 | 31 | Follow up: Suppose there are lots of incoming s, say s1, s2, ..., sk where k >= 109, and you want to check one by one to see if t has its subsequence. In this scenario, how would you change your code? 32 | Accepted 33 | 1.1M 34 | Submissions 35 | 2.4M 36 | Acceptance Rate 37 | 48.0% 38 | 39 | */ 40 | 41 | function isSubsequence(s: string, t: string): boolean { 42 | let sIdx = 0 43 | for (let i = 0; i < t.length; i++) { 44 | if (s[sIdx] === t[i]) sIdx++ 45 | } 46 | return sIdx === s.length 47 | } 48 | -------------------------------------------------------------------------------- /Typescript/80__medium_Remove Duplicates from Sorted Array II.ts: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | 80. Remove Duplicates from Sorted Array II 4 | Medium 5 | 6.1K 6 | 1.1K 7 | Companies 8 | Given an integer array nums sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears at most twice. The relative order of the elements should be kept the same. 9 | 10 | Since it is impossible to change the length of the array in some languages, you must instead have the result be placed in the first part of the array nums. More formally, if there are k elements after removing the duplicates, then the first k elements of nums should hold the final result. It does not matter what you leave beyond the first k elements. 11 | 12 | Return k after placing the final result in the first k slots of nums. 13 | 14 | Do not allocate extra space for another array. You must do this by modifying the input array in-place with O(1) extra memory. 15 | 16 | Custom Judge: 17 | 18 | The judge will test your solution with the following code: 19 | 20 | int[] nums = [...]; // Input array 21 | int[] expectedNums = [...]; // The expected answer with correct length 22 | 23 | int k = removeDuplicates(nums); // Calls your implementation 24 | 25 | assert k == expectedNums.length; 26 | for (int i = 0; i < k; i++) { 27 | assert nums[i] == expectedNums[i]; 28 | } 29 | If all assertions pass, then your solution will be accepted. 30 | 31 | 32 | 33 | Example 1: 34 | 35 | Input: nums = [1,1,1,2,2,3] 36 | Output: 5, nums = [1,1,2,2,3,_] 37 | Explanation: Your function should return k = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively. 38 | It does not matter what you leave beyond the returned k (hence they are underscores). 39 | Example 2: 40 | 41 | Input: nums = [0,0,1,1,1,1,2,3,3] 42 | Output: 7, nums = [0,0,1,1,2,3,3,_,_] 43 | Explanation: Your function should return k = 7, with the first seven elements of nums being 0, 0, 1, 1, 2, 3 and 3 respectively. 44 | It does not matter what you leave beyond the returned k (hence they are underscores). 45 | 46 | 47 | Constraints: 48 | 49 | 1 <= nums.length <= 3 * 104 50 | -104 <= nums[i] <= 104 51 | nums is sorted in non-decreasing order. 52 | 53 | */ 54 | 55 | function removeDuplicates(nums: number[]): number { 56 | if (!nums || !nums.length) return 0 57 | //nums = [1,1,1,2,2,3] 58 | // ^ 59 | // [1,1, ] 60 | let k = 0 61 | let count = 1 62 | for (let i = 1; i < nums.length; i++) { 63 | if (nums[i] === nums[i - 1]) count++ 64 | else { 65 | count = 1 66 | } 67 | 68 | if (count <= 2) { 69 | k++ 70 | nums[k] = nums[i] 71 | } 72 | } 73 | return k + 1 74 | } 75 | -------------------------------------------------------------------------------- /Typescript/88__easy_Merge Sorted Array.ts: -------------------------------------------------------------------------------- 1 | /* 2 | You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements in nums1 and nums2 respectively. 3 | 4 | Merge nums1 and nums2 into a single array sorted in non-decreasing order. 5 | 6 | The final sorted array should not be returned by the function, but instead be stored inside the array nums1. To accommodate this, nums1 has a length of m + n, where the first m elements denote the elements that should be merged, and the last n elements are set to 0 and should be ignored. nums2 has a length of n. 7 | 8 | 9 | 10 | Example 1: 11 | 12 | Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 13 | Output: [1,2,2,3,5,6] 14 | Explanation: The arrays we are merging are [1,2,3] and [2,5,6]. 15 | The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1. 16 | Example 2: 17 | 18 | Input: nums1 = [1], m = 1, nums2 = [], n = 0 19 | Output: [1] 20 | Explanation: The arrays we are merging are [1] and []. 21 | The result of the merge is [1]. 22 | Example 3: 23 | 24 | Input: nums1 = [0], m = 0, nums2 = [1], n = 1 25 | Output: [1] 26 | Explanation: The arrays we are merging are [] and [1]. 27 | The result of the merge is [1]. 28 | Note that because m = 0, there are no elements in nums1. The 0 is only there to ensure the merge result can fit in nums1. 29 | */ 30 | 31 | /** 32 | Do not return anything, modify nums1 in-place instead. 33 | */ 34 | function merge(nums1: number[], m: number, nums2: number[], n: number): void { 35 | // nums1 = [1,2,3,0,5,6], m = 3, 36 | // ^ 37 | // nums2 = [2,5,6], n = 3 38 | // ^ 39 | let idx1 = m - 1 40 | let idx2 = n - 1 41 | for (let i = nums1.length - 1; i >= 0; i--) { 42 | if (idx2 < 0) break 43 | 44 | if (nums1[idx1] >= nums2[idx2]) { 45 | nums1[i] = nums1[idx1] 46 | idx1-- 47 | } else { 48 | nums1[i] = nums2[idx2] 49 | idx2-- 50 | } 51 | } 52 | } 53 | --------------------------------------------------------------------------------