diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c16356 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +facebook +test.js \ No newline at end of file diff --git a/1 Two Sum.js b/1 Two Sum.js deleted file mode 100644 index bbb0794..0000000 --- a/1 Two Sum.js +++ /dev/null @@ -1,26 +0,0 @@ -/** - * @param {number[]} nums - * @param {number} target - * @return {number[]} - */ -var twoSum = function(nums, target) { - var hash = {}; - - for(var i = 0; i < nums.length; i++){ - hash[nums[i]] = i; - } - - for(i = 0; i < nums.length; i++){ - var num = nums[i]; - var diff = target - num; - if(hash[diff] !== undefined && hash[diff] !== i){ - if(hash[diff] > i){ - return [i+1, hash[diff]+1]; - } else { - return [hash[diff]+1, i+1] - } - } - } - - return []; -}; \ No newline at end of file diff --git a/101 Symmetric Tree.js b/101 Symmetric Tree.js index a2876c3..b4084f9 100644 --- a/101 Symmetric Tree.js +++ b/101 Symmetric Tree.js @@ -1,3 +1,26 @@ +// Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). + +// For example, this binary tree [1,2,2,3,4,4,3] is symmetric: + +// 1 +// / \ +// 2 2 +// / \ / \ +// 3 4 4 3 +// But the following [1,2,2,null,3,null,3] is not: +// 1 +// / \ +// 2 2 +// \ \ +// 3 3 +// Note: +// Bonus points if you could solve it both recursively and iteratively. + +// Hide Company Tags LinkedIn Bloomberg Microsoft +// Hide Tags Tree Depth-first Search Breadth-first Search + + + /** * Definition for a binary tree node. * function TreeNode(val) { @@ -10,31 +33,22 @@ * @return {boolean} */ var isSymmetric = function(root) { - if(root === null){ - return true; - } - var queue = []; queue.push(root); - var temp = []; - var curCnt = 1; - var nextCnt = 0; - - while(queue.length !== 0){ - var p = queue.shift(); + while(queue.length !== 0) { + var len = queue.length; - if(p !== null){ - temp.push(p.left); - temp.push(p.right); + if(!isLevelSymmetric(queue)) { + return false; } - if(queue.length === 0){ - if(isPalindrome(temp)){ - queue = temp; - temp = []; - } else { - return false; + for(var i = 0; i < len; i++) { + var node = queue.shift(); + + if(node !== null) { + queue.push(node.left); + queue.push(node.right); } } } @@ -42,23 +56,19 @@ var isSymmetric = function(root) { return true; }; - -var isPalindrome = function(arr){ - var head = 0; - var tail = arr.length - 1; +function isLevelSymmetric(nodes) { + var len = nodes.length; + var beg = 0; + var end = len - 1; - while(head < tail){ - if(arr[head] && arr[tail]){ - if(arr[head].val !== arr[tail].val){ - return false; - } - } else if(arr[head] || arr[tail]){ + while(beg < end) { + if(nodes[beg] === null && nodes[end] === null || (nodes[beg] && nodes[end] && nodes[beg].val === nodes[end].val)) { + beg++; + end--; + } else { return false; } - - head++; - tail--; } return true; -} \ No newline at end of file +} diff --git a/103 Binary Tree Zigzag Level Order Traversal.js b/103 Binary Tree Zigzag Level Order Traversal.js index f0edc9c..ee258a0 100644 --- a/103 Binary Tree Zigzag Level Order Traversal.js +++ b/103 Binary Tree Zigzag Level Order Traversal.js @@ -1,3 +1,22 @@ +// Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between). + +// For example: +// Given binary tree [3,9,20,null,null,15,7], +// 3 +// / \ +// 9 20 +// / \ +// 15 7 +// return its zigzag level order traversal as: +// [ +// [3], +// [20,9], +// [15,7] +// ] +// Hide Company Tags LinkedIn Bloomberg Microsoft +// Hide Tags Tree Breadth-first Search Stack +// Hide Similar Problems (E) Binary Tree Level Order Traversal + /** * Definition for a binary tree node. * function TreeNode(val) { @@ -10,47 +29,50 @@ * @return {number[][]} */ var zigzagLevelOrder = function(root) { - var result = [] + // bfs if(!root) { - return result; + return []; } - var fromLeft = false; - var curLvl = []; - curLvl.push(root); - - var nextLvl = []; - var temp = []; - - while(curLvl.length !== 0) { - var p = curLvl.pop(); - temp.push(p.val); + var curLevel = []; + curLevel.push(root); + + var fromLeft = true; + var result = []; + var tmpResult = []; + var nextLevel = []; + + while(curLevel.length > 0) { + var len = curLevel.length; - if(fromLeft) { - if(p.left) { - nextLvl.push(p.left); - } - if(p.right) { - nextLvl.push(p.right); - } - } else { - if(p.right) { - nextLvl.push(p.right); - } - if(p.left) { - nextLvl.push(p.left); + for(var i = 0; i < len; i++) { + var node = curLevel.pop(); + tmpResult.push(node.val); + + if(fromLeft) { + if(node.left) { + nextLevel.push(node.left); + } + if(node.right) { + nextLevel.push(node.right); + } + } else { + if(node.right) { + nextLevel.push(node.right); + } + if(node.left) { + nextLevel.push(node.left); + } } } - if(curLvl.length === 0) { - fromLeft = !fromLeft; - result.push(temp); - temp = []; - curLvl = nextLvl; - nextLvl = []; - } + fromLeft = !fromLeft; + curLevel = nextLevel; + nextLevel = []; + result.push(tmpResult); + tmpResult = []; } - return result + return result; }; \ No newline at end of file diff --git a/11 Container With Most Water.js b/11 Container With Most Water.js index 4afac2b..3e1a596 100644 --- a/11 Container With Most Water.js +++ b/11 Container With Most Water.js @@ -1,3 +1,29 @@ +// 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. +// +// Note: You may not slant the container and n is at least 2. +// +// 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. +// +// Example: +// +// Input: [1,8,6,2,5,4,8,3,7] +// Output: 49 +// + + +// Given fixed set of vertical bars +// Min case +// +// . . +// . . . . +// . . . . . . + +// Max case +// +// . . +// . . . . +// . . . . . . + /** * @param {number[]} height * @return {number} @@ -6,17 +32,17 @@ var maxArea = function(height) { var left = 0; var right = height.length - 1; var maxVal = 0; - + while(left= height[right]){ right--; } else { left++; } } - + return maxVal; -}; \ No newline at end of file +}; diff --git a/112 Path Sum.js b/112 Path Sum.js index b9e0d9e..3ecd17f 100644 --- a/112 Path Sum.js +++ b/112 Path Sum.js @@ -24,4 +24,31 @@ var hasPathSum = function(root, sum) { } return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val); +}; + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {number} sum + * @return {boolean} + */ +var hasPathSum = function(root, sum) { + if (root === null) { + return false; + } + + var left = root.left; + var right = root.right; + + if (left === null && right === null) { + return root.val === sum; + } + + return hasPathSum(left, sum - root.val) || hasPathSum(right, sum - root.val); }; \ No newline at end of file diff --git a/114 Flatten Binary Tree to Linked List.js b/114 Flatten Binary Tree to Linked List.js index 2f68381..1b20145 100644 --- a/114 Flatten Binary Tree to Linked List.js +++ b/114 Flatten Binary Tree to Linked List.js @@ -16,12 +16,12 @@ var flatten = function(root) { var stack = []; var p = root; - + while(p !== null || stack.length !== 0){ if(p.right !== null){ stack.push(p.right); } - + if(p.left !== null){ // [!!!]point of confusing, if null then pop stack p.right = p.left; p.left = null; @@ -29,8 +29,31 @@ var flatten = function(root) { var node = stack.pop(); p.right = node; } - + p = p.right; } }; +// Recursive solution + +var flatten = function(root) { + if(root === null || (root.left === null && root.right === null)) { + return; + } + + var rootLeft = root.left; + var rootRight = root.right; + root.left = null; + root.right = null; + + flatten(rootLeft); + flatten(rootRight); + + root.right = rootLeft; + + var aux = root; + while(aux !== null && aux.right !== null) { + aux = aux.right; + } + aux.right = rootRight; +}; diff --git a/117 Populating Next Right Pointer.js b/117 Populating Next Right Pointer.js new file mode 100644 index 0000000..b357d44 --- /dev/null +++ b/117 Populating Next Right Pointer.js @@ -0,0 +1,69 @@ +// Follow up for problem "Populating Next Right Pointers in Each Node". + +// What if the given tree could be any binary tree? Would your previous solution still work? + +// Note: + +// You may only use constant extra space. +// For example, +// Given the following binary tree, +// 1 +// / \ +// 2 3 +// / \ \ +// 4 5 7 +// After calling your function, the tree should look like: +// 1 -> NULL +// / \ +// 2 -> 3 -> NULL +// / \ \ +// 4-> 5 -> 7 -> NULL +// Hide Company Tags Microsoft Bloomberg Facebook +// Hide Tags Tree Depth-first Search +// Hide Similar Problems (M) Populating Next Right Pointers in Each Node + + + +/** + * Definition for binary tree with next pointer. + * function TreeLinkNode(val) { + * this.val = val; + * this.left = this.right = this.next = null; + * } + */ + +/** + * @param {TreeLinkNode} root + * @return {void} Do not return anything, modify tree in-place instead. + */ +var connect = function(root) { + if(!root) { + return; + } + + // leftEnd is used to track the current left most node + var leftEnd = root; + + while(leftEnd !== null) { + var cur = leftEnd; + // dummy is used to point to the next level's leftEnd + var dummy = new TreeLinkNode(0); + var pre = dummy; + // for each level we use leftEnd and leftEnd next to achieve level traversal + while(cur !== null) { + if(cur.left !== null) { + pre.next = cur.left; + pre = cur.left; + } + + if(cur.right !== null) { + pre.next = cur.right; + pre = cur.right; + } + + cur = cur.next; + } + + leftEnd = dummy.next; + } +}; \ No newline at end of file diff --git a/117 Populating Next Right Pointers in Each Node II.js b/117 Populating Next Right Pointers in Each Node II.js new file mode 100644 index 0000000..e69de29 diff --git a/121 Best Time to Buy and Sell Stock.js b/121 Best Time to Buy and Sell Stock.js index 00ecd01..245e43c 100644 --- a/121 Best Time to Buy and Sell Stock.js +++ b/121 Best Time to Buy and Sell Stock.js @@ -1,7 +1,21 @@ -// Leetcode 121 -// Language: Javascript -// Problem: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ -// Author: Chihung Yu +// Say you have an array for which the ith element is the price of a given stock on day i. + +// If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit. + +// Example 1: +// Input: [7, 1, 5, 3, 6, 4] +// Output: 5 + +// max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price) +// Example 2: +// Input: [7, 6, 4, 3, 1] +// Output: 0 + +// In this case, no transaction is done, i.e. max profit = 0. +// Hide Company Tags Amazon Microsoft Bloomberg Uber Facebook +// Hide Tags Array Dynamic Programming +// Hide Similar Problems (M) Maximum Subarray (M) Best Time to Buy and Sell Stock II (H) Best Time to Buy and Sell Stock III (H) Best Time to Buy and Sell Stock IV (M) Best Time to Buy and Sell Stock with Cooldown + /** * @param {number[]} prices * @return {number} diff --git a/123 Best Time to Buy and Sell Stock III.js b/123 Best Time to Buy and Sell Stock III.js new file mode 100644 index 0000000..d073487 --- /dev/null +++ b/123 Best Time to Buy and Sell Stock III.js @@ -0,0 +1,41 @@ +// Say you have an array for which the ith element is the price of a given stock on day i. + +// Design an algorithm to find the maximum profit. You may complete at most two transactions. + +// Note: +// You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). + +// http://www.cnblogs.com/springfor/p/3877068.html + +/** + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(prices) { + // Calculate MaxProfit from 0 to x and MaxProfit from x + 1 to len - 1; + var profitFromZeroToX = []; + var profitFromXToEnd = []; + var min = prices[0]; + + // get max profit from 0 to x + for(var x = 1; x < prices.length; x++) { + var price = prices[x]; + min = Math.min(price, min); + profitFromZeroToX[x] = Math.max(profitFromZeroToX[x - 1] || 0, price - min); + } + // get max profit from i + 1 to end + var max = prices[prices.length - 1]; + for(x = prices.length - 2; x >= 0; x--) { + price = prices[x]; + max = Math.max(price, max); + profitFromXToEnd[x] = Math.max(profitFromXToEnd[x + 1] || 0, max - price); + } + + var maxProfit = 0; + for(x = 0; x < prices.length; x++) { + var maxProfitSeperateAtX = (profitFromZeroToX[x] || 0) + (profitFromXToEnd[x] || 0); + maxProfit = Math.max(maxProfitSeperateAtX, maxProfit); + } + + return maxProfit; +}; diff --git a/124 Binary Tree Maximum Path Sum.js b/124 Binary Tree Maximum Path Sum.js new file mode 100644 index 0000000..85ecde5 --- /dev/null +++ b/124 Binary Tree Maximum Path Sum.js @@ -0,0 +1,51 @@ +// Given a binary tree, find the maximum path sum. + +// For this problem, a path is defined as any sequence of nodes from some starting node to any node in the tree along the parent-child connections. The path does not need to go through the root. + +// For example: +// Given the below binary tree, + +// 1 +// / \ +// 2 3 +// Return 6. + + +// http://bangbingsyb.blogspot.com/2014/11/leetcode-binary-tree-maximum-path-sum.html +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +var maxPathSum = function(root) { + var maxVal = -Infinity; + findMaxPath(root); + return maxVal; + + function findMaxPath(node) { + if(!node) { + return 0; + } + + var leftVal = Math.max(findMaxPath(node.left), 0); + var rightVal = Math.max(findMaxPath(node.right), 0); + + var ps1 = node.val + Math.max(leftVal, rightVal); + // ps2 means taking this current node as parent node and stop there + var ps2 = node.val + leftVal + rightVal; + + // maxVal as if we end counting value here, what will be the maximum val + // leftVal and rightVal can be negative values + maxVal = Math.max.apply(null, [maxVal, ps1, ps2]); + + // return ps1 only since, ps2 cannot be combined with the parent node + // leftVal and rightVal can be negative values, however, we can to see if combining with values down below can give higher number + return ps1; + } +}; diff --git a/125 Valid Palindrome.js b/125 Valid Palindrome.js new file mode 100644 index 0000000..287e4cc --- /dev/null +++ b/125 Valid Palindrome.js @@ -0,0 +1,68 @@ +// Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases. + +// For example, +// "A man, a plan, a canal: Panama" is a palindrome. +// "race a car" is not a palindrome. + +// Note: +// Have you consider that the string might be empty? This is a good question to ask during an interview. + +// For the purpose of this problem, we define empty string as valid palindrome. + +// Hide Company Tags Microsoft Uber Facebook Zenefits +// Hide Tags Two Pointers String +// Hide Similar Problems (E) Palindrome Linked List + + +/** + * @param {string} s + * @return {boolean} + */ +var isPalindrome = function(s) { + s = s.toLowerCase(); + var beg = 0; + var end = s.length - 1; + + while(beg < end) { + if(!s[beg].match(/[a-z0-9]/)) { + beg++; + } else if(!s[end].match(/[a-z0-9]/)) { + end--; + } else if(s[beg] !== s[end]) { + return false; + } else { + end--; + beg++; + } + } + + return true; +}; + + +/** + * @param {string} s + * @return {boolean} + */ +var isPalindrome = function(s) { + var head = 0; + var tail = s.length - 1; + + s = s.toLowerCase(); + + while(head < tail) { + while(s[head] && !s[head].match(/[a-z0-9]/)) { + head++; + } + while(s[tail] && !s[tail].match(/[a-z0-9]/)) { + tail--; + } + if(head < tail && s[head] !== s[tail]) { + return false; + } + head++; + tail--; + } + + return true; +}; \ No newline at end of file diff --git a/126 Word Ladder II.js b/126 Word Ladder II.js new file mode 100644 index 0000000..1852354 --- /dev/null +++ b/126 Word Ladder II.js @@ -0,0 +1,30 @@ +// Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) from beginWord to endWord, such that: + +// Only one letter can be changed at a time +// Each intermediate word must exist in the word list +// For example, + +// Given: +// beginWord = "hit" +// endWord = "cog" +// wordList = ["hot","dot","dog","lot","log"] +// Return +// [ +// ["hit","hot","dot","dog","cog"], +// ["hit","hot","lot","log","cog"] +// ] +// Note: +// All words have the same length. +// All words contain only lowercase alphabetic characters. + +/** + * @param {string} beginWord + * @param {string} endWord + * @param {Set} wordList + * Note: wordList is a Set object, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set + * @return {string[][]} + */ +var findLadders = function(beginWord, endWord, wordList) { + +}; \ No newline at end of file diff --git a/127 Word Ladder.js b/127 Word Ladder.js index ae8bd3a..ddc0395 100644 --- a/127 Word Ladder.js +++ b/127 Word Ladder.js @@ -1,57 +1,141 @@ +// Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation sequence from beginWord to endWord, such that: + +// Only one letter can be changed at a time +// Each intermediate word must exist in the word list +// For example, + +// Given: +// beginWord = "hit" +// endWord = "cog" +// wordList = ["hot","dot","dog","lot","log"] +// As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", +// return its length 5. + +// Note: +// Return 0 if there is no such transformation sequence. +// All words have the same length. +// All words contain only lowercase alphabetic characters. +// Amazon LinkedIn Snapchat Facebook Yelp + + // Leetcode 127 // Language: Javascript // Problem: https://leetcode.com/problems/word-ladder/ // Author: Chihung Yu + /** * @param {string} beginWord * @param {string} endWord - * @param {set} wordDict + * @param {Set} wordList + * Note: wordList is a Set object, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set * @return {number} */ - -String.prototype.replaceAt = function(i, c){ - return this.substring(0,i) + c + this.substring(i+1); +var ladderLength = function(beginWord, endWord, wordList) { + var visited = new Set(); + var queue = []; + var level = 1; + var letters = 'abcdefghijklmnopqrstuvwxyz'; + queue.push(beginWord); + visited.add(beginWord); + + while(queue.length > 0) { + + var len = queue.length; + + for(var i = 0; i < len; i++) { + var word = queue.shift(); + + for(var j = 0; j < word.length; j++) { + for(var k = 0; k < letters.length; k++) { + var newWord = word.substring(0, j) + letters[k] + word.substring(j + 1); + + if(newWord === endWord) { + return level + 1; + } + if(wordList.has(newWord) && !visited.has(newWord)) { + queue.push(newWord); + visited.add(newWord); + } + } + } + } + + level++; + } + + return 0; }; - -var ladderLength = function(beginWord, endWord, wordDict) { - if(beginWord === null || endWord === null || beginWord.length !== endWord.length || beginWord.length === 0 || endWord.length === 0){ + +// will time exceeded. javascript hash is slower than set +var ladderLength = function(beginWord, endWord, wordList) { + if(beginWord === endWord) { return 0; - } + } var queue = []; - queue.push(beginWord); - var visited = new Set(); - visited.add(beginWord); + var visited = {}; + var count = 1; + var baseCharCode = 'a'.charCodeAt(0); - var level = 1; - var curLvlCnt = 1; - var nextLvlCnt = 0; + queue.push(beginWord); - while(queue.length !== 0){ - var cur = queue.shift(); - curLvlCnt--; + while(queue.length) { + var len = queue.length; - for(var i = 0; i < cur.length; i++){ - for(var j = 0; j < 26; j++){ - var char = String.fromCharCode('a'.charCodeAt(0) + j); - var word = cur.replaceAt(i,char); - - if(word === endWord){ - return level + 1; - } - if(wordDict.has(word) && !visited.has(word)){ - nextLvlCnt++; - queue.push(word); - visited.add(word); + for(var i = 0; i < len; i++) { + var word = queue.shift(); + + for(var j = 0; j < word.length; j++) { + for(var k = 0; k < 26; k++) { + var newChar = String.fromCharCode(baseCharCode + k); + var newWord = word.substring(0, j) + newChar + word.substring(j + 1); + + if(newWord === endWord) { + return count + 1; + } + + if(!visited[newWord] && wordList.has(newWord)) { + visited[newWord] = true; + queue.push(newWord); + } } - } - } - if(curLvlCnt === 0){ - curLvlCnt = nextLvlCnt; - nextLvlCnt = 0; - level++; + } } + + count++; } + return 0; }; + + + +Hi Thiago + +I very much appreciate that you took the time writing this warm welcoming letter and provided me the opportunity to come onsite visiting the team at Periscope. +After much thought, I've decided to accept offer at another company. It was really a tough call for me since I really like the product, role and people I met during my visit. +Again, I cannot thank you enough for your time, and support. It's been a great pleasure to know you and the team. I hope that we cross paths in the near future. + +Wish you, teams, and Periscope all the success. + +Regards, +Jerry + + + + +Hi Cynthia + +Thank your for patience and support along the way. +I very much appreciate that you took the time answering many of my questions about the Periscope, and role. + +After much thought, I've decided to accept offer at another company. It was really a tough call for me since I really like the product and people I met during my visit. + +Again, I cannot thank you enough for your time, and support. It's been a great pleasure to know you and the team. I hope that we cross paths in the near future. + +Wish you, teams, and Periscope all the success. + +Regards, +Jerry \ No newline at end of file diff --git a/128 Longest Consecutive Sequence.js b/128 Longest Consecutive Sequence.js new file mode 100644 index 0000000..8c18bcc --- /dev/null +++ b/128 Longest Consecutive Sequence.js @@ -0,0 +1,52 @@ +// Given an unsorted array of integers, find the length of the longest consecutive elements sequence. + +// For example, +// Given [100, 4, 200, 1, 3, 2], +// The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4. + +// Your algorithm should run in O(n) complexity. + +// Hide Company Tags Google Facebook +// Hide Tags Array Union Find +// Hide Similar Problems (M) Binary Tree Longest Consecutive Sequence + + +/** + * @param {number[]} nums + * @return {number} + */ +var longestConsecutive = function(nums) { + var maxLen = -Infinity; + var hash = {}; + + for(var i = 0; i < nums.length; i++) { + hash[nums[i]] = 1; + } + + var visited = {}; + + for(i = 0; i < nums.length; i++) { + var val = nums[i]; + if(visited[val]) { + continue; + } + visited[val] = true; + var len = 1; + var preVal = val - 1; + while(hash[preVal]) { + len++ + visited[preVal--] = true; + } + var nxtVal = val + 1; + while(hash[nxtVal]) { + len++ + visited[nxtVal++] = true; + } + + if(len > maxLen) { + maxLen = len; + } + } + + return maxLen; +}; \ No newline at end of file diff --git a/133 Clone Graph.js b/133 Clone Graph.js index d17f7f9..9d46c78 100644 --- a/133 Clone Graph.js +++ b/133 Clone Graph.js @@ -1,3 +1,32 @@ +// Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. + + +// OJ's undirected graph serialization: +// Nodes are labeled uniquely. + +// We use # as a separator for each node, and , as a separator for node label and each neighbor of the node. +// As an example, consider the serialized graph {0,1,2#1,2#2,2}. + +// The graph has a total of three nodes, and therefore contains three parts as separated by #. + +// First node is labeled as 0. Connect node 0 to both nodes 1 and 2. +// Second node is labeled as 1. Connect node 1 to node 2. +// Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle. +// Visually, the graph looks like the following: + +// 1 +// / \ +// / \ +// 0 --- 2 +// / \ +// \_/ + +// Pocket Gems Google Uber Facebook +// Hide Tags Depth-first Search Breadth-first Search Graph +// Hide Similar Problems (H) Copy List with Random Pointer + + + /** * Definition for undirected graph. * function UndirectedGraphNode(label) { @@ -19,22 +48,34 @@ var cloneGraph = function(graph) { } function dfs(node){ - var newNode = null; - - if(visited[node.label]){ - newNode = visited[node.label]; - }else{ - newNode = new UndirectedGraphNode(node.label); - visited[node.label] = newNode; - } + var newNode = visited[node.label] ? visited[node.label] : new UndirectedGraphNode(node.label); + visited[node.label] = newNode; for(var i = 0; i < node.neighbors.length; i++){ - if(!visited[node.neighbors[i].label]){ - newNode.neighbors.push(dfs(node.neighbors[i])); - }else{ - newNode.neighbors.push(visited[node.neighbors[i].label]); - } + var newNeighbor = visited[node.neighbors[i].label] ? visited[node.neighbors[i].label] : dfs(node.neighbors[i]); + newNode.neighbors.push(newNeighbor); } return newNode; } +}; + + +var cloneGraph = function(graph) { + if(!graph) { + return graph; + } else { + return dfs(graph, {}); + } + + function dfs(node, visited) { + var newNode = visited[node.label] = visited[node.label] || new UndirectedGraphNode(node.label); + + for(var i = 0; i < node.neighbors.length; i++) { + var neighbor = node.neighbors[i]; + newNode.neighbors[i] = visited[neighbor.label] = visited[neighbor.label] || dfs(neighbor, visited); + } + + return newNode; + } + }; \ No newline at end of file diff --git a/138 Copy List With Random Pointer.js b/138 Copy List With Random Pointer.js new file mode 100644 index 0000000..61a90cb --- /dev/null +++ b/138 Copy List With Random Pointer.js @@ -0,0 +1,46 @@ +// A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. + +// Return a deep copy of the list. + +// Hide Company Tags Amazon Microsoft Bloomberg Uber +// Show Tags +// Show Similar Problems + + +/** + * Definition for singly-linked list with a random pointer. + * function RandomListNode(label) { + * this.label = label; + * this.next = this.random = null; + * } + */ + +/** + * @param {RandomListNode} head + * @return {RandomListNode} + */ +var copyRandomList = function(head) { + var hashMap = {}; + var newHead = new RandomListNode(0); + newHead.next = copyList(head); + + function copyList(node) { + if(node === null) { + return node; + } + + if(hashMap[node.label]) { + return hashMap[node.label]; + } + + var newNode = new RandomListNode(node.label); + hashMap[node.label] = newNode; + + newNode.next = copyList(node.next); + newNode.random = copyList(node.random); + + return newNode; + } + + return newHead.next; +}; \ No newline at end of file diff --git a/139 Word Break.js b/139 Word Break.js index 3745fc2..d167ec9 100644 --- a/139 Word Break.js +++ b/139 Word Break.js @@ -1,32 +1,28 @@ -// Leetcode #139 -// Language: Javascript -// Problem: https://leetcode.com/problems/word-break/ -// Author: Chihung Yu /** * @param {string} s * @param {set} wordDict + * Note: wordDict is a Set object, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set * @return {boolean} */ var wordBreak = function(s, wordDict) { - if(wordDict === null || wordDict.size === 0){ + if(wordDict === null || wordDict.size === 0) { return false; } - - var t = []; - t[0] = true; - for(var i = 0; i} wordDict + * Note: wordDict is a Set object, see: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set + * @return {string[]} + */ +var wordBreak = function(s, wordDict) { + var result = []; + var solutions = []; + var len = s.length; + var possible = []; + + for(var i = 0; i <= s.length; i++) { + possible.push(true); + } + + getAllSolutions(0, s, wordDict, result, solutions, possible); + return solutions; +}; + +function getAllSolutions(start, s, wordDict, result, solutions, possible) { + if(start === s.length) { + solutions.push(result.join(' ')) // remove the last space + return; + } + + // loop through string from i to s.length + for(var i = start; i < s.length; i++) { + var piece = s.substring(start, i+1); + + // possible is to mark step whether i+1 to s.length have any possible words + if(wordDict.has(piece) && possible[i+1]) {// eliminate unnecessary search + result.push(piece); + var beforeChange = solutions.length; + getAllSolutions(i + 1, s, wordDict, result, solutions, possible); + if(solutions.length === beforeChange) { + possible[i+1] = false; + } + result.pop(); + } + } +} + + +var dict = new Set(); +dict.add('leet'); +dict.add('code'); +dict.add('cod'); +dict.add('de'); + +wordBreak('leetcode', dict) \ No newline at end of file diff --git a/141 Linked List Cycle.js b/141 Linked List Cycle.js index a4d76ad..ea7e272 100644 --- a/141 Linked List Cycle.js +++ b/141 Linked List Cycle.js @@ -2,6 +2,44 @@ // Language: Javascript // Problem: https://leetcode.com/problems/linked-list-cycle/ // Author: Chihung Yu +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ + +/** + * @param {ListNode} head + * @return {boolean} + */ +// var hasCycle = function(head) { +// if(head === null || head.next === null){ +// return false; +// } + +// var faster = head.next; +// var slower = head; + +// while(faster && slower){ +// if(faster.val === slower.val){ +// return true; +// } +// faster = faster.next; + +// if(faster === null){ +// return false; +// } else { +// faster = faster.next; +// } + +// slower = slower.next; +// } + +// return false; +// }; + /** * Definition for singly-linked list. * function ListNode(val) { @@ -15,26 +53,27 @@ * @return {boolean} */ var hasCycle = function(head) { - if(head === null || head.next === null){ + if (head === null) { return false; } + + var node1 = head; + var node2 = head; + node2 = node2.next; - var faster = head.next; - var slower = head; - - while(faster && slower){ - if(faster.val === slower.val){ + while(node1 !== null && node2 !== null) { + if (node1.val === node2.val) { return true; } - faster = faster.next; + + node1 = node1.next; + node2 = node2.next; - if(faster === null){ - return false; - } else { - faster = faster.next; + if (node2 !== null) { + node2 = node2.next; } - slower = slower.next; + } return false; diff --git a/144 Binary Tree Preorder Traversal My Submissions Question.js b/144 Binary Tree Preorder Traversal My Submissions Question.js index d13dbba..e2447e4 100644 --- a/144 Binary Tree Preorder Traversal My Submissions Question.js +++ b/144 Binary Tree Preorder Traversal My Submissions Question.js @@ -14,21 +14,60 @@ * @return {number[]} */ +// var preorderTraversal = function(root) { +// var result = []; + +// traverse(root, result); + +// return result; +// }; + +// function traverse(node, result) { +// if(!node) { +// return; +// } + +// result.push(node.val); + +// traverse(node.left, result); +// traverse(node.right, result); +// } + + + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ var preorderTraversal = function(root) { var result = []; + + if(root === null) { + return result; + } + + var stack = []; + stack.push(root); - traverse(root, result); + while(stack.length) { + var node = stack.pop(); + result.push(node.val); + + if(node.right !== null) { + stack.push(node.right); + } + if(node.left !== null) { + stack.push(node.left); + } + } return result; }; -function traverse(node, result) { - if(!node) { - return; - } - - result.push(node.val); - - traverse(node.left, result); - traverse(node.right, result); -} \ No newline at end of file diff --git a/145 Binary Tree Post Order Traversal.js b/145 Binary Tree Post Order Traversal.js new file mode 100644 index 0000000..52c28f9 --- /dev/null +++ b/145 Binary Tree Post Order Traversal.js @@ -0,0 +1,48 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +var postorderTraversal = function(root) { + var result = []; + var stack = []; + var prev = null; + var curr = null; + + if(root === null) { + return result; + } + + stack.push(root); + + // use prev and curr to figure out the direction of tree traversal + while(stack.length !== 0) { + curr = stack[stack.length - 1]; + + if(prev === null || prev.left === curr || prev.right === curr) { // traverse down the tree + if(curr.left !== null) { + stack.push(curr.left); + } else if(curr.right !== null) { + stack.push(curr.right); + } + } else if(curr.left === prev) { //traverse up the tree from the left + if(curr.right !== null) { + stack.push(curr.right); + } + } else { + // it means that curr === prev + result.push(curr.val); + stack.pop(); + } + + prev = curr; + } + + return result; +}; \ No newline at end of file diff --git a/146 LRU Cache.js b/146 LRU Cache.js new file mode 100644 index 0000000..0fdfda3 --- /dev/null +++ b/146 LRU Cache.js @@ -0,0 +1,206 @@ +class Node { + constructor(key, val) { + this.key = key; + this.val = val; + this.next = null; + this.prev = null; + } +} +/** + * @constructor + */ +var LRUCache = function(capacity) { + this.list = null; + this.map = new Map(); + this.head = null; + this.tail = null; + this.capacity = capacity; + this.curSize = 0; +}; + +/** + * @param {number} key + * @returns {number} + */ +LRUCache.prototype.get = function(key) { + let node = this.map.get(key); + if (!node) { + return -1; + } + + if (node === this.head) { + return node.val; + } + + // remove node from list + if (node === this.tail) { + this.tail.prev.next = null; + this.tail = this.tail.prev; + } else { + node.prev.next = node.next; + node.next.prev = node.prev; + } + + // insert node to head + node.next = this.head; + this.head.prev = node; + this.head = node; + + return node.val; +}; + +/** + * @param {number} key + * @param {number} value + * @returns {void} + */ +LRUCache.prototype.set = function(key, value) { + let newNode = new Node(key, value); + + if (this.curSize === 0) { + this.tail = newNode; + } else { + newNode.next = this.head; + this.head.prev = newNode; + } + + this.head = newNode; + // this.curSize++; + + // update + if (this.map.get(key)) { + let oldNode = this.map.get(key); + + // remove node + if (oldNode === this.tail) { + this.tail = this.tail.prev; + this.tail.next = null; + } else { + oldNode.prev.next = oldNode.next; + oldNode.next.prev = oldNode.prev; + } + } else { + this.curSize++ + if (this.curSize > this.capacity) { + //delete tail + this.map.delete(this.tail.key); + this.tail = this.tail.prev; + this.tail.next = null; + this.curSize--; + } + } + + this.map.set(key, newNode); +}; + + + + + + + + + + +// Second Implementation + + +function DoublyLinkListNode(key, value) { + this.key = key; + this.value = value; + this.prev = this.next = null; +} + +/** + * @constructor + */ +var LRUCache = function(capacity) { + this.head = this.tail = null; + this.maxCapacity = capacity; + this.currSize = 0; + this.hash = {}; +}; + +/** + * @param {number} key + * @returns {number} + */ +LRUCache.prototype.get = function(key) { + if(!this.hash[key]) { + return -1; + } + + this.moveToHead(key); + return this.hash[key].value; +}; + +/** + * @param {number} key + * @param {number} value + * @returns {void} + */ +LRUCache.prototype.set = function(key, value) { + if(this.maxCapacity <= 0) { + return; + } + + if(!this.hash[key]) { + + if(this.currSize === this.maxCapacity) { + this.removeLast(); + this.currSize--; + } + + this.hash[key] = new DoublyLinkListNode(key, value); + this.currSize++; + } + + this.hash[key].value = value; + this.moveToHead(key); +}; + +LRUCache.prototype.removeLast = function() { + if(this.tail === null) { + return; + } + + delete this.hash[this.tail.key]; + var newTail = this.tail.prev; + + if(newTail === null) { + this.head = this.tail = null; + return; + } + + this.tail.prev = null; + newTail.next = null; + this.tail = newTail; +} + +LRUCache.prototype.moveToHead = function(key) { + var newHead = this.hash[key]; + + if(this.head === null && this.tail === null) { + this.head = this.tail = newHead; + } + + if(newHead === this.head) { + return; + } + + if(newHead === this.tail) { + this.tail = newHead.prev; + } + + if(newHead.prev) { + newHead.prev.next = newHead.next; + } + if(newHead.next) { + newHead.next.prev = newHead.prev; + } + + newHead.prev = null; + newHead.next = this.head; + this.head.prev = newHead; + this.head = newHead; +} \ No newline at end of file diff --git a/148 Sort List.js b/148 Sort List.js index 6aa1d40..86e8a69 100644 --- a/148 Sort List.js +++ b/148 Sort List.js @@ -1,3 +1,5 @@ +// Sort a linked list in O(n log n) time using constant space complexity. + /** * Definition for singly-linked list. * function ListNode(val) { @@ -28,13 +30,18 @@ var sortList = function(head) { return newHead; function sort(len) { + // there will be no case of len = 0 which is caused by 1/2 if(len === 1) { var temp = head; - head = head.next; + // !!! important: moving pointer to the next + // e.g. 1->2->3->4 + // head-> 1 + // now head will be point to 2 + head = head.next; temp.next = null; return temp; } - + // there will be no case of len = 0 which is caused by 1/2 var leftHead = sort(parseInt(len/2)); var rightHead = sort(len - parseInt(len/2)); var newHead = merge(leftHead, rightHead); diff --git a/149 Max Points on a Line.js b/149 Max Points on a Line.js new file mode 100644 index 0000000..9615ee9 --- /dev/null +++ b/149 Max Points on a Line.js @@ -0,0 +1,69 @@ +解这个平面几何题有3个要点: + +1. 如何判断共线? +两点成一直线,所以两点没有共线不共线之说。对于点p1(x1, y1),p2(x2, y2),p3(x3, y3)来说,共线的条件是p1-p2连线的斜率与p1-p3连线的斜率相同,即 +(y2-y1)/(x2-x1) = (y3-y1)/(x3-x1) +所以对共线的n点,其中任意两点连线的斜率相同。 + +2. 如何判断最多的共线点? +对于每个点p出发,计算该点到所有其他点qi的斜率,对每个斜率统计有多少个点符合。其中最多的个数加1(出发点本身)即为最多的共线点。 + +3. 特殊情况 +当x1 = x2,y1!=y2时,为垂直连线。计算斜率时分母为0会出错。 +当x1 = x2,y1 = y2时,两点重合。则(x2, y2)和所有(x1, y1)的连线共线。 + + + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +class Solution { +public: + int maxPoints(vector &points) { + int maxPts = 0; + for(int i=0; i comSlopes; + + for(int j=i+1; j nums[i-1]){ // very important, same as line 40, remove duplicate as 111 will only run once 1-> rather tan 1 1 1 - target = 0 - nums[i]; + if(i === 0 || nums[i] > nums[i-1]){ // very important, same as line 40, remove duplicate as 111 will only run once 1-> rather than 1 1 1 + var target = 0 - nums[i]; j = i + 1; k = len - 1; diff --git a/150 Evaluate Reverse Polish Notation.js b/150 Evaluate Reverse Polish Notation.js index 6fbae82..5d6eb24 100644 --- a/150 Evaluate Reverse Polish Notation.js +++ b/150 Evaluate Reverse Polish Notation.js @@ -1,7 +1,14 @@ -// Leetcode #150 -// Language: Javascript -// Problem: https://leetcode.com/problems/evaluate-reverse-polish-notation/ -// Author: Chihung Yu +// Evaluate the value of an arithmetic expression in Reverse Polish Notation. + +// Valid operators are +, -, *, /. Each operand may be an integer or another expression. + +// Some examples: +// ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 +// ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6 +// Hide Company Tags LinkedIn +// Hide Tags Stack +// Hide Similar Problems (H) Basic Calculator (H) Expression Add Operators + /** * @param {string[]} tokens * @return {number} @@ -9,29 +16,30 @@ var evalRPN = function(tokens) { var stack = []; - for(var i = 0; i < tokens.length; i++){ - var t = tokens[i]; - - if(t === '+'){ - var x = parseInt(stack.pop()); - var y = parseInt(stack.pop()); - stack.push(x + y); - } else if(t === '-'){ - x = parseInt(stack.pop()); - y = parseInt(stack.pop()); - stack.push(y - x); - } else if(t === '*'){ - x = parseInt(stack.pop()); - y = parseInt(stack.pop()); - stack.push(parseInt(y * x)); - } else if(t === '/'){ - x = parseInt(stack.pop()); - y = parseInt(stack.pop()); - stack.push(parseInt(y / x)); + for(var i = 0; i < tokens.length; i++) { + var token = tokens[i]; + var val1,val2; + var val = parseInt(token); + if(!isNaN(val)) { + stack.push(val); } else { - stack.push(t); + val2 = stack.pop(); + val1 = stack.pop(); + + if(token === '*') { + stack.push(parseInt(val1 * val2)); + } else if(token === '/') { + stack.push(parseInt(val1 / val2)); + } else if(token === '-') { + stack.push(val1 - val2); + } else if(token === '+') { + stack.push(val1 + val2); + } } } - var num = stack.pop(); - return parseInt(num); -}; \ No newline at end of file + + return stack.pop(); +}; + + +console.log(evalRPN([ 12, 12, 12, '*', '+', 3, 4, '-', '+' ] )); diff --git a/152 Maximum Product Subarray.js b/152 Maximum Product Subarray.js index b3aff51..8366765 100644 --- a/152 Maximum Product Subarray.js +++ b/152 Maximum Product Subarray.js @@ -1,12 +1,22 @@ +// Find the contiguous subarray within an array (containing at least one number) which has the largest product. + +// For example, given the array [2,3,-2,4], +// the contiguous subarray [2,3] has the largest product = 6. + +// Hide Company Tags LinkedIn +// Hide Tags Array Dynamic Programming +// Show Similar Problems + + + // Leetcode #152 // Language: Javascript // Problem: https://leetcode.com/problems/maximum-product-subarray/ -// Author: Chihung Yu /** * @param {number[]} nums * @return {number} */ -// http://www.programcreek.com/2014/03/leetcode-maximum-product-subarray-java/ +// reference: http://www.programcreek.com/2014/03/leetcode-maximum-product-subarray-java/ var maxProduct = function(nums) { if(nums === null || nums.length === 0){ return 0; diff --git a/153 Find Minimum in Rotated Sorted Array.js b/153 Find Minimum in Rotated Sorted Array.js index 7e98c2f..a01c797 100644 --- a/153 Find Minimum in Rotated Sorted Array.js +++ b/153 Find Minimum in Rotated Sorted Array.js @@ -10,10 +10,10 @@ var findMin = function(nums) { var s = 0; var e = nums.length - 1; var min; - + while(s nums[e]) { @@ -21,8 +21,17 @@ var findMin = function(nums) { } else { return nums[s]; } - + } - + return Math.min(nums[e], nums[s]); -}; \ No newline at end of file +}; + +// Another shorter solution; +var findMin = function(nums) { + var i = 0; + while(i < nums.length - 1 && nums[i] < nums[i + 1]) { + i++; + } + return (i === nums.length - 1)? nums[0] : nums[i + 1] +}; diff --git a/156 Binary Tree Upside Down.js b/156 Binary Tree Upside Down.js new file mode 100644 index 0000000..f2eb627 --- /dev/null +++ b/156 Binary Tree Upside Down.js @@ -0,0 +1,86 @@ +// Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that shares the same parent node) or empty, flip it upside down and turn it into a tree where the original right nodes turned into left leaf nodes. Return the new root. + +// For example: +// Given a binary tree {1,2,3,4,5}, +// 1 +// / \ +// 2 3 +// / \ +// 4 5 +// return the root of the binary tree [4,5,2,#,#,3,1]. +// 4 +// / \ +// 5 2 +// / \ +// 3 1 +// confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ. + +// Hide Company Tags LinkedIn +// Hide Tags Tree +// Show Similar Problems + + + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {TreeNode} + */ +var upsideDownBinaryTree = function(root) { + var newRoot = root; + + generateUpsideDownHelper(root); + + function generateUpsideDownHelper(root) { + if(!root) { + return root; + } + + if(!root.left && !root.right) { + newRoot = root; + return root; + } + + if(root.left) { + var ret = generateUpsideDownHelper(root.left); + ret.left = root.right; + ret.right = root; + root.left = null; + root.right = null; + } + + return root; + } + return newRoot; +}; + + +// simpler solution +var upsideDownBinaryTree = function(root) { + // second condition ensure the left most child will be the new root + if (!root || (!root.left && !root.right)) { + return root; + } + + let newRoot = upsideDownBinaryTree(root.left); + console.log(newRoot.val, root.left) + + root.left.left = root.right; + root.left.right = root; + + // cannot work if we sub root.left with newRoot + // since new root is always the left most child + // [doesn't work] newRoot.left = root.right; + // [doesn't work] newRoot.right = root; + + root.left = null; + root.right = null; + + return newRoot; +}; diff --git a/157 Read N Characters Given Read4.js b/157 Read N Characters Given Read4.js new file mode 100644 index 0000000..5ea66de --- /dev/null +++ b/157 Read N Characters Given Read4.js @@ -0,0 +1,60 @@ +// The API: int read4(char *buf) reads 4 characters at a time from a file. + +// The return value is the actual number of characters read. For example, it returns 3 if there is only 3 characters left in the file. + +// By using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file. + +// Note: +// The read function will only be called once for each test case. + +// Hide Company Tags Facebook +// Hide Tags String +// Hide Similar Problems (H) Read N Characters Given Read4 II - Call multiple times + + +/** + * Definition for read4() + * + * @param {character[]} buf Destination buffer + * @return {number} The number of characters read + * read4 = function(buf) { + * ... + * }; + */ + +/** + * @param {function} read4() + * @return {function} + */ +var solution = function(read4) { + /** + * @param {character[]} buf Destination buffer + * @param {number} n Maximum number of characters to read + * @return {number} The number of characters read + */ + return function(buf, n) { + var eof = false; + var total = 0; + var temp = Array(4); + + while(!eof && total < n) { + // read4 will populate temp with read characters, and return count ... + var count = read4(temp); + + if(count < 4) { + eof = true; + } + + count = Math.min(count, n - total); + + for(var i = 0; i < count; i++) { + buf[total++] = temp[i]; + } + } + + return total; + }; +}; + + +// [tricky] [important] \ No newline at end of file diff --git a/158 Read N Characters Give Read4 II - Call Multiple Times.js b/158 Read N Characters Give Read4 II - Call Multiple Times.js new file mode 100644 index 0000000..2230a88 --- /dev/null +++ b/158 Read N Characters Give Read4 II - Call Multiple Times.js @@ -0,0 +1,98 @@ +// The API: int read4(char *buf) reads 4 characters at a time from a file. + +// The return value is the actual number of characters read. For example, it returns 3 if there is only 3 characters left in the file. + +// By using the read4 API, implement the function int read(char *buf, int n) that reads n characters from the file. + +// Note: +// The read function may be called multiple times. + +// Hide Company Tags Bloomberg Google Facebook +// Hide Tags String +// Hide Similar Problems (E) Read N Characters Given Read4 + + + +/** + * Definition for read4() + * + * @param {character[]} buf Destination buffer + * @return {number} The number of characters read + * read4 = function(buf) { + * ... + * }; + */ + +/** + * @param {function} read4() + * @return {function} + */ +var solution = function(read4) { + let bufRead = []; + let count = 0; // how many characters read with read4 + let i = 0; + + /** + * @param {character[]} buf Destination buffer + * @param {number} n Maximum number of characters to read + * @return {number} The number of characters read + */ + return function(buf, n) { + let numChrRead = 0; + + while (numChrRead < n) { + if (i === 0) { + count = read4(bufRead); + } + + while (i < count && numChrRead < n) { + buf[numChrRead++] = bufRead[i++]; + } + + // read4 buffer used up, start over + if (i === count) { + i = 0; + } + + // end of file + if (count < 4) { + break; + } + } + + return numChrRead; + }; +}; + +var solution = function(read4) { + /** + * @param {character[]} buf Destination buffer + * @param {number} n Number of characters to read + * @return {number} The number of actual characters read + */ + var read4Buff = []; + var read4NumCharRead = 0; + var read4Remain = 0; + + return function(buf, n) { + var numCharRead = 0; + + // Need to run read4 N times to get n char + while(numCharRead < n) { + // If everything is already read in read4 buffer, re-read + if (read4NumCharRead === read4Remain) { + read4NumCharRead = 0; + read4Remain = read4(read4Buff); + } + while(read4NumCharRead < read4Remain && numCharRead < n) { + buf[numCharRead++] = read4Buff[read4NumCharRead++]; + } + if (read4Remain < 4) { + break; + } + + } + + return numCharRead; + }; +}; \ No newline at end of file diff --git a/159 Longest Substring with At Most Two Disctinct Characters.js b/159 Longest Substring with At Most Two Disctinct Characters.js new file mode 100644 index 0000000..aae47ba --- /dev/null +++ b/159 Longest Substring with At Most Two Disctinct Characters.js @@ -0,0 +1,87 @@ +// https://segmentfault.com/a/1190000003790746 + +/** + * @param {string} s + * @return {number} + */ + + // Time O(N) + // Space O(1) +var lengthOfLongestSubstringTwoDistinct = function(s) { + var longestSubstr = ""; + var maxLength = 0; + var start = 0; + var map = new Map(); + + for(var i = 0; i < s.length; i++) { + var c = s.charAt(i); + + // if map already contains two distrinct chars and the char is new to the map + if(map.size > 1 && map.get(c) === undefined) { + // Calc substring len before the new char + if(i - start > maxLength) { + // Should not include i, since i is the new distinct char's index + longestSubstr = s.substring(start, i); + maxLength = longestSubstr.length; + } + // Find the left most char + var leftMost = s.length; + map.forEach((charIdx, key)=> { + if(charIdx < leftMost) { + leftMost = charIdx; + } + }); + + start = leftMost + 1; + map.delete(s[leftMost]); + } + + map.set(c, i); + } + + if(s.length - start > maxLength) { + longestSubstr = s.substring(start, s.length); + maxLength = longestSubstr.length; + } + + return maxLength; +}; + + + + +/** + * @param {string} s + * @return {number} + */ +var lengthOfLongestSubstringTwoDistinct = function(s) { + var map = new Map(); + var start = 0; + var maxLen = 0; + + for(var i = 0; i < s.length; i++) { + var c = s[i]; + if (map.size === 2 && map.get(c) === undefined) { + var curStr; + if (i - start > maxLen) { + maxLen = i - start; + } + var leftMost = s.length; + map.forEach((charIdx, key) => { + if (charIdx < leftMost) { + leftMost = charIdx; + } + }); + start = leftMost + 1; + map.delete(s[leftMost]); + } + + map.set(c, i); + } + + if (s.length - start > maxLen) { + maxLen = s.length - start; + } + + return maxLen; +}; \ No newline at end of file diff --git a/16 3Sum Closest.js b/16 3Sum Closest.js index 2308633..66c0350 100644 --- a/16 3Sum Closest.js +++ b/16 3Sum Closest.js @@ -7,7 +7,7 @@ var threeSumClosest = function(nums, target) { if(nums === null || nums.length < 2){ return null; } - + if(nums.length === 3){ return nums.reduce(function(prev,cur){return prev + cur;}); } @@ -16,18 +16,18 @@ var threeSumClosest = function(nums, target) { var closest = Infinity; nums.sort(function(a,b){return a > b ? 1 : -1;}); - + for(var i = 0; i < nums.length; i++){ var j = i + 1; var k = nums.length - 1; while(j < k){ var sum = nums[j] + nums[k] + nums[i]; var diff = sum - target; - + if(diff === 0){ return sum; } - + if(sum < target){ diff = target - sum; j++; @@ -35,15 +35,45 @@ var threeSumClosest = function(nums, target) { diff = sum - target; k-- } - + if(diff < closest){ closest = diff; result = sum; } } - + while(i < (nums.length-1) && nums[i] === nums[i+1]) i++; } - + return result; -}; \ No newline at end of file +}; + +//Shorter solution +var threeSumClosest = function(nums, target) { + var closest = Number.Infinity; + var gap = -1; + + nums.sort(function(a, b) { return a - b }); + for(var i = 0; i < nums.length - 2; i++) { + var low = i + 1; + var high = nums.length - 1; + + while(low < high) { + var sum = nums[i] + nums[low] + nums[high]; + partialGap = Math.abs(target - sum); + if(partialGap < gap || gap === -1) { + gap = partialGap; + closest = sum; + } + + if(sum === target) { + return target; + } else if (sum < target) { + low++; + } else { + high--; + } + } + } + return closest; +}; diff --git a/161 One Edit Distance.js b/161 One Edit Distance.js new file mode 100644 index 0000000..f53ae22 --- /dev/null +++ b/161 One Edit Distance.js @@ -0,0 +1,81 @@ +// Given two strings S and T, determine if they are both one edit distance apart. + +// Hide Company Tags Snapchat Uber Facebook Twitter +// Hide Tags String +// Hide Similar Problems (H) Edit Distance + + +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ + +// tricky question! + +var isOneEditDistance = function(s, t) { + if(s.length > t.length) { + var tmp = s; + s = t; + t = tmp; + } + + if((t.length - s.length) > 1) { + return false; + } + + var found = false; + + for(var i = 0, j = 0; i < s.length; i++, j++) { + if(s[i] !== t[j]) { + + if(found) { + return false; + } + + found = true; + + if(s.length < t.length) { + i--; + } + } + } + + return found || s.length < t.length; +}; + + +var isOneEditDistance = function(s, t) { + if(s.length > t.length) { + var tmp = s; + s = t; + t = tmp; + } + + if(t.length - s.length > 1) { + return false; + } + + + var i = 0; + var j = 0; + var diff = 0; + + while(i < s.length && j < t.length) { + if(s[i] !== t[j]) { + if(diff !== 0) { + return false; + } + diff++; + + if(t.length !== s.length) { + i--; + } + } + + i++; + j++; + } + + return diff === 1 || (t.length !== s.length && (t.length - j) === 1); +}; \ No newline at end of file diff --git a/163 Missing Ranges.js b/163 Missing Ranges.js new file mode 100644 index 0000000..ce31cfb --- /dev/null +++ b/163 Missing Ranges.js @@ -0,0 +1,39 @@ +/** + * @param {number[]} nums + * @param {number} lower + * @param {number} upper + * @return {string[]} + */ +var findMissingRanges = function(nums, lower, upper) { + var missing = []; + if (nums.length === 0) { + missing.push(getRange(lower,upper)); + return missing; + } + + // Only need to search range between lower and upper + var next = lower; + for(var i = 0; i < nums.length; i++) { + var val = nums[i]; + + if (val < next) { + continue; + } else if (val === next) { + next++; + continue; + } + // val > next + missing.push(getRange(next, val-1)); + next = val + 1; + } + + if (next <= upper) { + missing.push(getRange(next, upper)); + } + + return missing; +}; + +function getRange(lower, upper) { + return upper === lower ? `${lower}` : `${lower}->${upper}`; +} \ No newline at end of file diff --git a/17 Letter Combinations of a Phone Number.js b/17 Letter Combinations of a Phone Number.js index a5843a0..f61b313 100644 --- a/17 Letter Combinations of a Phone Number.js +++ b/17 Letter Combinations of a Phone Number.js @@ -1,65 +1,57 @@ +// Given a digit string, return all possible letter combinations that the number could represent. + +// A mapping of digit to letters (just like on the telephone buttons) is given below. + + + +// Input:Digit string "23" +// Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. +// Note: +// Although the above answer is in lexicographical order, your answer could be in any order you want. + +// Hide Company Tags Amazon Dropbox Google Uber Facebook +// Hide Tags Backtracking String +// Hide Similar Problems (M) Generate Parentheses (M) Combination Sum + + /** * @param {string} digits * @return {string[]} */ + +var numToLetters = { + '0': ' ', + '1': '', + '2': 'abc', + '3': 'def', + '4': 'ghi', + '5': 'jkl', + '6': 'mno', + '7': 'pqrs', + '8': 'tuv', + '9': 'wxyz' +}; + var letterCombinations = function(digits) { - var result = []; + var res = []; - if(digits === null || digits.length === 0){ - return result; + if(digits.length === 0) { + return res; } - var str = []; - - generate(digits, 0, str, result); - return result; -}; - -var generate = function(digits, depth, str, result){ - if(digits.length === depth){ - result.push(str.join('')); - return; + function dfs(digits, idx, curr) { + if(idx === digits.length) { + res.push(curr); + return; + } + + var letters = numToLetters[digits[idx]]; + + for(var i = 0; i < letters.length; i++) { + dfs(digits, idx + 1, curr + letters[i]); + } } - - var letters = convertDigitToLetters(digits[depth]); - for(var i = 0; i < letters.length; i++){ - var letter = letters[i]; - str.push(letter); - generate(digits, depth + 1, str, result); - str.pop(); - } -} - -var convertDigitToLetters = function(c){ - if(c === '1'){ - return ''; - } - if(c === '2'){ - return 'abc'; - } - if(c === '3'){ - return 'def'; - } - if(c === '4'){ - return 'ghi'; - } - if(c === '5'){ - return 'jkl'; - } - if(c === '6'){ - return 'mno'; - } - if(c === '7'){ - return 'pqrs'; - } - if(c === '8'){ - return 'tuv'; - } - if(c === '9'){ - return 'wxyz'; - } - if(c === '0'){ - return ' '; - } -} \ No newline at end of file + dfs(digits, 0, ''); + return res; +}; \ No newline at end of file diff --git a/170 Two Sum III - Data structure design.js b/170 Two Sum III - Data structure design.js new file mode 100644 index 0000000..d437be3 --- /dev/null +++ b/170 Two Sum III - Data structure design.js @@ -0,0 +1,45 @@ +/** + * initialize your data structure here + * @constructor + */ +var TwoSum = function() { + this.hashmap = new Map(); +}; + +/** + * Add the number to an internal data structure. + * @param {number} input + * @returns {void} + */ +TwoSum.prototype.add = function(input) { + this.hashmap[input] = this.hashmap[input] || 0; + this.hashmap[input]++; +}; + +/** + * Find if there exists any pair of numbers which sum is equal to the value. + * @param {number} val + * @returns {boolean} + */ +TwoSum.prototype.find = function(val) { + for(var key in this.hashmap) { + var diff = val - parseInt(key); + + if(diff === parseInt(key)){ + if(this.hashmap[diff] >= 2) { + return true; + } + } else if(this.hashmap[diff] >= 1) { + return true; + } + } + + return false; +}; + +/** + * Your TwoSum object will be instantiated and called as such: + * var twoSum = new TwoSum(); + * twoSum.add(number); + * twoSum.find(value); + */ \ No newline at end of file diff --git a/173 Binary Search Tree Iterator.js b/173 Binary Search Tree Iterator.js index 26535de..08de1f2 100644 --- a/173 Binary Search Tree Iterator.js +++ b/173 Binary Search Tree Iterator.js @@ -1,3 +1,18 @@ +// Implement an iterator over a binary search tree (BST). Your iterator will be initialized with the root node of a BST. + +// Calling next() will return the next smallest number in the BST. + +// Note: next() and hasNext() should run in average O(1) time and uses O(h) memory, where h is the height of the tree. + +// Credits: +// Special thanks to @ts for adding this problem and creating all test cases. + +// Hide Company Tags LinkedIn Google Facebook Microsoft +// Hide Tags Tree Stack Design +// Hide Similar Problems (M) Binary Tree Inorder Traversal (M) Flatten 2D Vector (M) Zigzag Iterator (M) Peeking Iterator (M) Inorder Successor in BST + + + /** * Definition for binary tree * function TreeNode(val) { diff --git a/18. 4Sum.js b/18. 4Sum.js new file mode 100644 index 0000000..7ba27ae --- /dev/null +++ b/18. 4Sum.js @@ -0,0 +1,41 @@ +/** + * @param {number[]} nums + * @param {number} target + * @return {number[][]} + */ +var fourSum = function(nums, target) { + var results = []; + nums.sort(function(a,b) { return a - b }); + for(var i = 0; i < nums.length - 3; i++) { + while(i > 0 && i < nums.length - 3 && nums[i] === nums[i - 1]) { + i++; + } + for(var j = i + 1; j < nums.length - 2; j++) { + while(j > i + 1 && j < nums.length - 2 && nums[j] === nums[j - 1]) { + j++; + } + var low = j + 1; + var high = nums.length - 1; + var newTarget = target - (nums[i] + nums[j]); + while(low < high) { + partialSum = nums[low] + nums[high]; + if(partialSum === newTarget) { + results.push([nums[i], nums[j], nums[low], nums[high]]); + high--; + low++; + while(low < high && nums[low] === nums[low - 1]) { + low++; + } + while(low < high && nums[high] === nums[high + 1]) { + high--; + } + } else if (partialSum > newTarget) { + high--; + } else { + low++; + } + } + } + } + return results; +}; diff --git a/186 Reverse Words in a String II.js b/186 Reverse Words in a String II.js new file mode 100644 index 0000000..2c0a405 --- /dev/null +++ b/186 Reverse Words in a String II.js @@ -0,0 +1,37 @@ +// Given an input string, reverse the string word by word. A word is defined as a sequence of non-space characters. + +// The input string does not contain leading or trailing spaces and the words are always separated by a single space. + +// For example, +// Given s = "the sky is blue", +// return "blue is sky the". + +// Could you do it in-place without allocating extra space? + +/** + * @param {character[]} str + * @return {void} Do not return anything, modify the string in-place instead. + */ +var reverseWords = function(str) { + var arr = str; + + reverse(arr, 0, arr.length - 1); + var last = 0; + + for(var i = 0; i <= arr.length; i++) { + if(arr[i] === ' ' || i === arr.length) { + reverse(arr, last, i - 1); + last = i + 1; + } + } + + function reverse(arr, beg, end) { + while(beg < end) { + var tmp = str[beg]; + str[beg] = str[end]; + str[end] = tmp; + beg++; + end--; + } + } +}; \ No newline at end of file diff --git a/187 Repeated DNA Sequences.js b/187 Repeated DNA Sequences.js new file mode 100644 index 0000000..56dfb34 --- /dev/null +++ b/187 Repeated DNA Sequences.js @@ -0,0 +1,34 @@ +// All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When studying DNA, it is sometimes useful to identify repeated sequences within the DNA. + +// Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule. + +// For example, + +// Given s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT", + +// Return: +// ["AAAAACCCCC", "CCCCCAAAAA"]. +// Hide Company Tags LinkedIn +// Hide Tags Hash Table Bit Manipulation + + +/** + * @param {string} s + * @return {string[]} + */ +var findRepeatedDnaSequences = function(s) { + var hash = {}; + var result = []; + + for(var i = 10; i <= s.length; i++) { + var substr = s.substring(i - 10, i); + if(hash[substr] === undefined) { + hash[substr] = 1; + } else if(hash[substr] === 1) { + hash[substr]++; + result.push(substr); + } + } + + return result; +}; \ No newline at end of file diff --git a/188 Best Time to Buy and Sell Stock IV.js b/188 Best Time to Buy and Sell Stock IV.js new file mode 100644 index 0000000..5339baa --- /dev/null +++ b/188 Best Time to Buy and Sell Stock IV.js @@ -0,0 +1,57 @@ +// memory limit exceeded +// Time O(n*k) +// Space (n*k) +// ref: http://blog.csdn.net/fightforyourdream/article/details/14503469 + +/** + * @param {number} k + * @param {number[]} prices + * @return {number} + */ +var maxProfit = function(k, prices) { + var len = prices.length; + + if(len === 0) { + return 0; + } + var globalBest = initMatrix(len, k + 1); + var localBest = initMatrix(len, k + 1); + + // matrix[row][col] + // row is ith day + // col is jth transaction + // localBest[i][j] is the max profit across i day, with j transaction where there is transaction happening on i day + // globalBest[i][j] is the max profit across i day, with j transaction + + for(var i = 1; i < len; i++) { + var diff = prices[i] - prices[i - 1]; + + for(var j = 1; j <= k; j++) { + + // globalBest[i - 1][j - 1] + Math.max(diff, 0) + // -> current global best before ith day and jth transaction, Math.max(diff, 0) means we can take this transaction into account or discard it. + // localBest[i - 1][j] + diff + // -> since localBest[i][j] means the last transaction has to happen on this day, regardless transaction lost money or not, we need to add it. + // In addition, localBest[i - 1][j] + diff -> does not add transaction count e.g. + // [buy, sell and buy, sell] is the same as [buy, nothing, sell] since it's all continuous actions + localBest[i][j] = Math.max(globalBest[i - 1][j - 1] + Math.max(diff, 0), localBest[i - 1][j] + diff); + globalBest[i][j] = Math.max(globalBest[i - 1][j], localBest[i][j]); + } + } + + return globalBest[len - 1][k]; +}; + + +function initMatrix(days, transactions) { + var matrix = []; + + for(var i = 0; i < days; i++) { + matrix.push([]); + for(var j = 0; j < transactions; j++) { + matrix[i][j] = 0; + } + } + + return matrix; +} \ No newline at end of file diff --git a/190 Reverse Bits.js b/190 Reverse Bits.js index 76911a0..04d3eb1 100644 --- a/190 Reverse Bits.js +++ b/190 Reverse Bits.js @@ -9,11 +9,15 @@ var reverseBits = function(n) { var result = 0; - for(var i = 0; i < 32; i++){ + for(var i = 0; i < 31; i++){ result <<= 1; result |= n & 1; - n >>= 1; + + n >>>= 1; + console.log(result, n); } return Math.abs(result); -}; \ No newline at end of file +}; + +console.log(reverseBits(4294967295)); \ No newline at end of file diff --git a/191 Number of 1 Bits.js b/191 Number of 1 Bits.js index fc84d8a..a26280e 100644 --- a/191 Number of 1 Bits.js +++ b/191 Number of 1 Bits.js @@ -2,6 +2,20 @@ // Language: Javascript // Problem: https://leetcode.com/problems/number-of-1-bits/ // Author: Chihung Yu + +// Write a function that takes an unsigned integer and returns the number of ’1' bits it has (also known as the Hamming weight). + +// For example, the 32-bit integer ’11' has binary representation 00000000000000000000000000001011, so the function should return 3. + +// Credits: +// Special thanks to @ts for adding this problem and creating all test cases. + +// Hide Company Tags Microsoft Apple +// Hide Tags Bit Manipulation +// Hide Similar Problems (E) Reverse Bits (E) Power of Two (M) Counting Bits + + + /** * @param {number} n - a positive integer * @return {number} diff --git a/198 House Robber.js b/198 House Robber.js index 6d2be47..bc8bc12 100644 --- a/198 House Robber.js +++ b/198 House Robber.js @@ -1,3 +1,16 @@ +// You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night. + +// Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police. + +// Credits: +// Special thanks to @ifanchu for adding this problem and creating all test cases. Also thanks to @ts for adding additional test cases. + +// Hide Company Tags LinkedIn Airbnb +// Show Tags +// Show Similar Problems + + + // Leetcode #198 // Language: Javascript // Problem: https://leetcode.com/problems/house-robber/ @@ -23,4 +36,22 @@ var rob = function(nums) { } return Math.max(even,odd); -}; \ No newline at end of file +}; + + +// var rob = function(nums) { +// var dp = []; + +// if(!nums || nums.length === 0) { +// return 0; +// } +// // dp[i] is the max amount can rob on ith house + +// for(var i = 0; i < nums.length; i++){ +// var num = nums[i]; +// dp[i] = Math.max((dp[i-2] || 0) + num, (dp[i-1] || 0)); +// } + +// return dp[nums.length - 1]; +// }; + diff --git a/199 Binary Tree Right Side View.js b/199 Binary Tree Right Side View.js index 6ecf0c8..4ca72c2 100644 --- a/199 Binary Tree Right Side View.js +++ b/199 Binary Tree Right Side View.js @@ -1,7 +1,13 @@ -// Leetcode #199 -// Language: Javascript -// Problem: https://leetcode.com/problems/binary-tree-right-side-view/ -// Author: Chihung Yu +// For example: +// Given the following binary tree, +// 1 <--- +// / \ +// 2 3 <--- +// \ \ +// 5 4 <--- +// You should return [1, 3, 4]. + + /** * Definition for a binary tree node. * function TreeNode(val) { @@ -14,37 +20,34 @@ * @return {number[]} */ var rightSideView = function(root) { - var answer = []; - - if(root === null){ - return answer; + var result = []; + + if(root === null) { + return result; } - - var queue = []; + + queue = []; queue.push(root); - var curLvlCnt = queue.length; - var nextLvlCnt = 0; - while(queue.length !== 0){ - var node = queue.shift(); - curLvlCnt--; + while(queue.length > 0) { + var len = queue.length; - if(node.left){ - queue.push(node.left); - nextLvlCnt++; - } - if(node.right){ - queue.push(node.right); - nextLvlCnt++; + for(var i = 0; i < len; i++) { + var node = queue.shift(); + + if(node.left) { + queue.push(node.left); + } + + if(node.right) { + queue.push(node.right); + } + + if(i === len - 1) { + result.push(node.val); + } } - - if(curLvlCnt <= 0){ - answer.push(node.val); - curLvlCnt = nextLvlCnt; - nextLvlCnt = 0; - } - } - return answer; -} \ No newline at end of file + return result; +}; \ No newline at end of file diff --git a/2 Add Two Numbers.js b/2 Add Two Numbers.js deleted file mode 100644 index 2a492bf..0000000 --- a/2 Add Two Numbers.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * Definition for singly-linked list. - * function ListNode(val) { - * this.val = val; - * this.next = null; - * } - */ -/** - * @param {ListNode} l1 - * @param {ListNode} l2 - * @return {ListNode} - */ -var addTwoNumbers = function(l1, l2) { - if(l1 === null || l2 === null){ - return l1 || l2; - } - - var result = new ListNode(0); - var cur = result; - var p = l1; - var q = l2; - var carry = 0; - - while(p || q){ - var qval; - var pval; - - if(q){ - qval = q.val; - q = q.next; - } else { - qval = 0; - } - - if(p){ - pval = p.val; - p = p.next; - } else { - pval = 0; - } - - var val = qval + pval + carry; - - if(val > 9){ - carry = 1; - val %= 10; - } else { - carry = 0; - } - - cur.next = new ListNode(val); - cur = cur.next; - } - - if(carry !== 0){ - cur.next = new ListNode(1); - } - - return result.next; - -}; \ No newline at end of file diff --git a/20 Valid Parentheses.js b/20 Valid Parentheses.js index 746b67e..748fa9a 100644 --- a/20 Valid Parentheses.js +++ b/20 Valid Parentheses.js @@ -27,5 +27,26 @@ var isValid = function(s) { index++; } + return stack.length === 0; +}; + +// second attempt + +var isValid = function(s) { + var stack = []; + + for(var i = 0; i < s.length; i++) { + var chr = s[i]; + + if(chr === '(' || chr === '{' || chr === '[') { + stack.push(chr); + } else if(chr === ')' || chr === '}' || chr === ']') { + var top = stack.pop(); + if(!top || (top === '(' && chr !== ')') || (top === '{' && chr !== '}') || (top === '[' && chr !== ']')) { + return false; + } + } + } + return stack.length === 0; }; \ No newline at end of file diff --git a/200 Number of Islands.js b/200 Number of Islands.js index a755398..ba829ec 100644 --- a/200 Number of Islands.js +++ b/200 Number of Islands.js @@ -1,51 +1,94 @@ +// Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water. + +// Example 1: + +// 11110 +// 11010 +// 11000 +// 00000 +// Answer: 1 + +// Example 2: + +// 11000 +// 11000 +// 00100 +// 00011 +// Answer: 3 /** * @param {character[][]} grid * @return {number} */ var numIslands = function(grid) { - var count = 0; - - var rows = grid.length; + var visited = []; + var row = grid.length; - if(rows === 0){ - return count; + if(!grid || row === 0) { + return 0; } - var cols = grid[0].length; - - if(cols === 0) { - return count; - } - - for(i = 0; i < rows; i++) { - for(var j = 0; j < cols; j++) { - if(grid[i][j] === "1") { + var col = grid[0].length; + var count = 0; + for(var i = 0; i < row; i++) { + for(var j = 0; j < col; j++) { + if(grid[i][j] === '1') { count++; - walk(grid, i, j, rows, cols); + traverse(i, j, grid, row, col); } } } + return count; }; -var walk = function(grid, x, y, rows, cols) { - if(grid[x][y] === "1") { - grid[x][y] = "0"; +var traverse = function(i, j, grid, row, col) { + if((0 <= i && i < row) && (0 <= j && j < col) && grid[i][j] === '1') { + grid[i][j] = '2'; + + + traverse(i + 1, j, grid, row, col); + traverse(i, j + 1, grid, row, col); + traverse(i - 1, j, grid, row, col); + traverse(i, j - 1, grid, row, col); } +} - if((x + 1) < rows && grid[x+1][y] === "1") { - walk(grid, x + 1, y, rows, cols); - } +// non recusion +/** + * @param {character[][]} grid + * @return {number} + */ +var numIslands = function(grid) { + var count = 0; - if((x - 1) >= 0 && grid[x-1][y] === "1") { - walk(grid, x - 1, y, rows, cols); + function traverseIsland(i, j, grid) { + var stack = []; + + stack.push([i, j]); + + while(stack.length) { + var pair = stack.pop(); + i = pair[0]; + j = pair[1]; + + if(i >= 0 && i < grid.length && j >= 0 && j < grid[0].length && grid[i][j] === '1') { + grid[i][j] = '2'; + stack.push([i + 1, j]); + stack.push([i - 1, j]); + stack.push([i, j + 1]); + stack.push([i, j - 1]); + } + } } - if((y + 1) < cols && grid[x][y+1] === "1") { - walk(grid, x, y + 1, rows, cols); + for(var i = 0; i < grid.length; i++) { + for(var j = 0; j < grid[0].length; j++) { + if(grid[i][j] === '1') { + traverseIsland(i, j, grid); + count++; + } + } } - if((y - 1) >= 0 && grid[x][y-1] === "1") { - walk(grid, x, y - 1, rows, cols); - } -} \ No newline at end of file + return count; +}; \ No newline at end of file diff --git a/204 Count Primes.js b/204 Count Primes.js index 6fcb9c7..21c4d2d 100644 --- a/204 Count Primes.js +++ b/204 Count Primes.js @@ -1,3 +1,7 @@ +// Description: + +// Count the number of prime numbers less than a non-negative number, n. + // Leetcode #204 // Language: Javascript // Problem: https://leetcode.com/problems/count-primes/ diff --git a/205 Isomorphic Strings.js b/205 Isomorphic Strings.js index 457370d..9e00acb 100644 --- a/205 Isomorphic Strings.js +++ b/205 Isomorphic Strings.js @@ -1,36 +1,49 @@ -// Leetcode #205 -// Language: Javascript -// Problem: https://leetcode.com/problems/isomorphic-strings/ -// Author: Chihung Yu +// Given two strings s and t, determine if they are isomorphic. + +// Two strings are isomorphic if the characters in s can be replaced to get t. + +// 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. + +// For example, +// Given "egg", "add", return true. + +// Given "foo", "bar", return false. + +// Given "paper", "title", return true. + +// Note: +// You may assume both s and t have the same length. + +// Hide Company Tags LinkedIn +// Hide Tags Hash Table +// Hide Similar Problems (E) Word Pattern + + + /** * @param {string} s * @param {string} t * @return {boolean} */ var isIsomorphic = function(s, t) { - if(s === null || t === null){ - return true; + if(s.length !== t.length) { + return false; } var hash1 = {}; var hash2 = {}; - for(var i = 0; i < s.length; i++){ - var sc = s[i]; - var tc = t[i]; - - hash1[sc] = tc; - hash2[tc] = sc; + for(var i = 0; i < s.length; i++) { + hash1[s[i]] = t[i]; + hash2[t[i]] = s[i]; } - var result1 = ""; - var result2 = ""; + var result1 = ''; + var result2 = ''; - for(i = 0; i < s.length; i++){ - sc = s[i] - tc = t[i]; - result1 += hash1[sc]; - result2 += hash2[tc]; + for(i = 0; i < s.length; i++) { + result1 += hash1[s[i]]; + result2 += hash2[t[i]]; } return result1 === t && result2 === s; diff --git a/206 Reverse Linked List.js b/206 Reverse Linked List.js index f3d4f14..9b95909 100644 --- a/206 Reverse Linked List.js +++ b/206 Reverse Linked List.js @@ -2,6 +2,14 @@ // Language: Javascript // Problem: https://leetcode.com/problems/reverse-linked-list/ // Author: Chihung Yu + + +// Reverse a singly linked list. + +// Uber Facebook Twitter Zenefits Amazon Microsoft Snapchat Apple Yahoo Bloomberg Yelp Adobe +// Show Tags +// Show Similar Problems + /** * Definition for singly-linked list. * function ListNode(val) { @@ -14,19 +22,15 @@ * @return {ListNode} */ var reverseList = function(head) { - if(head === null){ - return head; - } + var curr = head; + var prev = null; - var cur = head; - var pre = null; - - while(cur){ - var post = cur.next; - cur.next = pre; - pre = cur; - cur = post; + while(curr) { + var next = curr.next; + curr.next = prev; + prev = curr; + curr = next; } - return pre; + return prev; }; \ No newline at end of file diff --git a/207 Course Schedule.js b/207 Course Schedule.js index 1b4d16c..8919e63 100644 --- a/207 Course Schedule.js +++ b/207 Course Schedule.js @@ -2,23 +2,92 @@ // Language: Javascript // Problem: https://leetcode.com/problems/course-schedule/ // Author: Chihung Yu + +// Non-recursion version 144ms +// more generic solution to problem that doesn't need information of numCourses and can deal with duplicated prerequisites + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {boolean} + */ +var canFinish = function(numCourses, prerequisites) { + var courseWithOtherCoursesDependOn = {}; + var courseDependsOnOtherCourses = {}; + + prerequisites.forEach((prerequisite)=> { + var prereqCourse = prerequisite[1]; + var courseToTake = prerequisite[0] + + + courseWithOtherCoursesDependOn[prereqCourse] = courseWithOtherCoursesDependOn[prereqCourse] || new Set(); + courseWithOtherCoursesDependOn[prereqCourse].add(courseToTake); + + courseDependsOnOtherCourses[prereqCourse] = courseDependsOnOtherCourses[prereqCourse] || new Set(); + courseDependsOnOtherCourses[courseToTake] = courseDependsOnOtherCourses[courseToTake] || new Set(); + courseDependsOnOtherCourses[courseToTake].add(prereqCourse); + }); + + var courseWithNoDependencies = []; + + for(var i in courseDependsOnOtherCourses) { + if(courseDependsOnOtherCourses[i].size === 0) { + courseWithNoDependencies.push(i); + } + } + + while(courseWithNoDependencies.length > 0) { + var rootCourse = courseWithNoDependencies.shift(); + + if(courseWithOtherCoursesDependOn[rootCourse]) { + courseWithOtherCoursesDependOn[rootCourse].forEach((childCourse)=> { + courseDependsOnOtherCourses[childCourse].delete(parseInt(rootCourse)); + + if(courseDependsOnOtherCourses[childCourse].size === 0) { + courseWithNoDependencies.push(childCourse + ''); + } + }); + } + } + + for(i in courseDependsOnOtherCourses) { + if(courseDependsOnOtherCourses[i].size !== 0) { + return false; + } + } + + return true; +}; + + + +// recursion 132ms + /** * @param {number} numCourses * @param {number[][]} prerequisites * @return {boolean} */ + // http://www.cnblogs.com/Liok3187/p/4752700.html + var constructGraph = function(numNodes, pre) { var nodes = []; for (var i = 0; i < numNodes; i++) { var node = {}; node.neighbors = []; - nodes[i] = node; + nodes.push(node); } for (var j = 0; j < pre.length; j++) { - var s = pre[j][1]; - var d = pre[j][0]; - nodes[s].neighbors.push(nodes[d]); + var requiredCourse = pre[j][1]; + var course = pre[j][0]; + // pushing course that require required-course to it's neighbor + // when we go to the required-course, and traverse it's neighbors, we want to make sure that those neighbor doesn't have others that nodes + // that required those neighbor plus those neighbor's required-course + // example [1,0], [0,2], [2,1] + // 1 required 0, 0 required 2, and 2 required 1 + // it creates loop + nodes[requiredCourse].neighbors.push(nodes[course]); } return nodes; } @@ -42,9 +111,12 @@ var canFinish = function(numCourses, prerequisites) { var nodes = constructGraph(numCourses, prerequisites); for (var i = 0; i < nodes.length; i++) { - console.log('nodes i',nodes[i]) - var hasCycle = dfs(nodes[i], []); + var parent = []; + var hasCycle = dfs(nodes[i], parent); + if (hasCycle) return false; } return true; -}; \ No newline at end of file +}; + + diff --git a/209 Minimum Size Subarray Sum.js b/209 Minimum Size Subarray Sum.js index 7fc3302..ae6b33e 100644 --- a/209 Minimum Size Subarray Sum.js +++ b/209 Minimum Size Subarray Sum.js @@ -1,30 +1,58 @@ // http://blog.csdn.net/lisonglisonglisong/article/details/45666975 +// http://www.cnblogs.com/grandyang/p/4501934.html + +// Given an array of n positive integers and a positive integer s, find the minimal length of a subarray of which the sum ≥ s. If there isn't one, return 0 instead. + +// For example, given the array [2,3,1,2,4,3] and s = 7, +// the subarray [4,3] has the minimal length under the problem constraint. + +// click to show more practice. + +// Credits: +// Special thanks to @Freezen for adding this problem and creating all test cases. + +// Hide Company Tags Facebook +// Hide Tags Array Two Pointers Binary Search +// Hide Similar Problems (H) Minimum Window Substring (M) Maximum Size Subarray Sum Equals k + /** * @param {number} s * @param {number[]} nums * @return {number} */ + +// O(n) solution var minSubArrayLen = function(s, nums) { var sum = 0; var left = 0; - var right = -1; - var len = nums.length; + var right = 0; var minLen = Infinity; - while(right < len) { - while(right < len && sum < s) { - sum += nums[++right]; - } - if(sum >= s) { - minLen = Math.min(right - left + 1, minLen); - sum -= nums[left]; - left++; + while(right < nums.length) { + while(right < nums.length && sum < s) { + sum += nums[right++]; } + while(sum >= s) { + minLen = Math.min(minLen, right - left); + sum -= nums[left++]; + } } - - - return minLen > len ? 0 : minLen; -}; \ No newline at end of file + return minLen > nums.length ? 0 : minLen; +}; + +// The O(NlogN) solution is to sum up the array +// [1,2,3,4,5] becomes [1,3,6,10,15] +// then iterate through array from index 0 to nums.length - 1 +// for each value in the summed array +// binary search values after that index so the difference becomes greater than s +// example +// s = 8 +// at index 0 with value 1 look between [3,6,10,15] using binary search. +// we can find that at value 10 the difference is 10 - 1 = 9 the minLen is index 3 - 1 + 1 = 3 +// then we check index 1 with value 3 and binary search [6,10,15] we can find that at value 15 we have difference 15 - 3 = 12 +// the distance is index 4 - 1 + 1 = 4 + +// console.log(minSubArrayLen(11, [1,2,3,4,5])); \ No newline at end of file diff --git a/21 Merge Two Sorted Lists.js b/21 Merge Two Sorted Lists.js index f72bacf..b126758 100644 --- a/21 Merge Two Sorted Lists.js +++ b/21 Merge Two Sorted Lists.js @@ -1,3 +1,9 @@ +// Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists. + +// Hide Company Tags Amazon LinkedIn Apple Microsoft +// Hide Tags Linked List +// Hide Similar Problems (H) Merge k Sorted Lists (E) Merge Sorted Array (M) Sort List (M) Shortest Word Distance II + /** * Definition for singly-linked list. * function ListNode(val) { diff --git a/210 Course Schedule II.js b/210 Course Schedule II.js new file mode 100644 index 0000000..fb3c78c --- /dev/null +++ b/210 Course Schedule II.js @@ -0,0 +1,98 @@ +// There are a total of n courses you have to take, labeled from 0 to n - 1. + +// Some courses may have prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a pair: [0,1] + +// Given the total number of courses and a list of prerequisite pairs, return the ordering of courses you should take to finish all courses. + +// There may be multiple correct orders, you just need to return one of them. If it is impossible to finish all courses, return an empty array. + +// For example: + +// 2, [[1,0]] +// There are a total of 2 courses to take. To take course 1 you should have finished course 0. So the correct course order is [0,1] + +// 4, [[1,0],[2,0],[3,1],[3,2]] +// There are a total of 4 courses to take. To take course 3 you should have finished both courses 1 and 2. Both courses 1 and 2 should be taken after you finished course 0. So one correct course order is [0,1,2,3]. Another correct ordering is[0,2,1,3]. + +// Note: +// The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more about how a graph is represented. + +// click to show more hints. + +// Hide Company Tags Facebook Zenefits +// Hide Tags Depth-first Search Breadth-first Search Graph Topological Sort +// Hide Similar Problems (M) Course Schedule (H) Alien Dictionary (M) Minimum Height Trees + + +// 160ms + +/** + * @param {number} numCourses + * @param {number[][]} prerequisites + * @return {number[]} + */ +var findOrder = function(numCourses, prerequisites) { + var courseWithOtherCoursesDependOn = {}; + var courseDependsOnOtherCourses = {}; + + prerequisites.forEach((prerequisite)=> { + var prereqCourse = prerequisite[1]; + var courseToTake = prerequisite[0] + + + courseWithOtherCoursesDependOn[prereqCourse] = courseWithOtherCoursesDependOn[prereqCourse] || new Set(); + courseWithOtherCoursesDependOn[prereqCourse].add(courseToTake); + + courseDependsOnOtherCourses[prereqCourse] = courseDependsOnOtherCourses[prereqCourse] || new Set(); + courseDependsOnOtherCourses[courseToTake] = courseDependsOnOtherCourses[courseToTake] || new Set(); + courseDependsOnOtherCourses[courseToTake].add(prereqCourse); + }); + + var courseWithNoDependencies = []; + + for(var i in courseDependsOnOtherCourses) { + if(courseDependsOnOtherCourses[i].size === 0) { + courseWithNoDependencies.push(i); + } + } + + + // pretty much the same as Course Schedule I. Just need to add those non root + var courseOrders = []; + var hasCourseOrders = {}; + + while(courseWithNoDependencies.length > 0) { + var rootCourse = courseWithNoDependencies.shift(); + + courseOrders.push(parseInt(rootCourse)); + hasCourseOrders[parseInt(rootCourse)] = true; + + if(courseWithOtherCoursesDependOn[rootCourse]) { + courseWithOtherCoursesDependOn[rootCourse].forEach((childCourse)=> { + courseDependsOnOtherCourses[childCourse].delete(parseInt(rootCourse)); + + if(courseDependsOnOtherCourses[childCourse].size === 0) { + courseWithNoDependencies.push(childCourse + ''); + } + }); + } + } + + for(i in courseDependsOnOtherCourses) { + if(courseDependsOnOtherCourses[i].size !== 0) { + return []; + } + } + + if(courseOrders.length < numCourses) { + for(i = 0; i < numCourses; i++) { + if(!hasCourseOrders[i]) { + courseOrders.push(i); + } + } + } + + return courseOrders; +}; + +console.log(findOrder(3, [[1,0]])); \ No newline at end of file diff --git a/211 Add and Search Word - Data structure design.js b/211 Add and Search Word - Data structure design.js index 3f9697f..8994bc6 100644 --- a/211 Add and Search Word - Data structure design.js +++ b/211 Add and Search Word - Data structure design.js @@ -1,20 +1,38 @@ -// Leetcode #211 -// Language: Javascript -// Problem: https://leetcode.com/problems/add-and-search-word-data-structure-design/ -// Author: Chihung Yu +// Design a data structure that supports the following two operations: -var TrieNode = function(){ - this.iskey = false; - this.children = []; -} +// void addWord(word) +// bool search(word) +// search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter. + +// For example: +// addWord("bad") +// addWord("dad") +// addWord("mad") +// search("pad") -> false +// search("bad") -> true +// search(".ad") -> true +// search("b..") -> true +// Note: +// You may assume that all words are consist of lowercase letters a-z. +// click to show hint. + +// Hide Company Tags Facebook +// Hide Tags Backtracking Trie Design +// Hide Similar Problems (M) Implement Trie (Prefix Tree) + +function TrieNode(chr) { + this.val = chr; + this.isWord = false; + this.children = []; +} /** * @constructor */ var WordDictionary = function() { - this.root = new TrieNode(); + this.root = new TrieNode(null, false); }; /** @@ -24,22 +42,13 @@ var WordDictionary = function() { */ WordDictionary.prototype.addWord = function(word) { var node = this.root; - - for(var i = 0; i < word.length; i++){ - var key = charKeyFromA(word[i]); - if(!node.children[key]){ - node.children[key] = new TrieNode(); - } - - node = node.children[key]; + for(var i = 0; i < word.length; i++) { + var chr = word[i]; + node.children[chr] = node.children[chr] || new TrieNode(chr); + node = node.children[chr]; } - node.iskey = true; -}; - -charKeyFromA = function(c){ - var a = 'a'.charCodeAt(0); - return c.charCodeAt(0) - a; + node.isWord = true; }; /** @@ -49,28 +58,30 @@ charKeyFromA = function(c){ * contain the dot character '.' to represent any one letter. */ WordDictionary.prototype.search = function(word) { - return searchWord(this.root, word, 0); -}; - -var searchWord = function(node, word, index){ - if(word.length === index){ - return node.iskey; - } - - var c = word[index]; + var node = this.root; - if(c === "."){ - for(var i = 0; i < 26; i++){ - if(node.children[i] && searchWord(node.children[i], word, index+1)){ - return true; + function dfs(node, word, i) { + if(i === word.length) { + return node.isWord; + } + + var chr = word[i]; + + if(chr === '.') { + for(var key in node.children) { + if(dfs(node.children[key], word, i + 1)) { + return true; + } } + } else if(node.children[chr]) { + return dfs(node.children[chr], word, i + 1); } + return false; - } else { - var key = charKeyFromA(c); - return !!(node.children[key] && searchWord(node.children[key], word, index+1)); } -} + + return dfs(node, word, 0); +}; /** * Your WordDictionary object will be instantiated and called as such: diff --git a/212 Word Search II.js b/212 Word Search II.js new file mode 100644 index 0000000..929f597 --- /dev/null +++ b/212 Word Search II.js @@ -0,0 +1,95 @@ +// Given a 2D board and a list of words from the dictionary, find all words in the board. + +// Each word must be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once in a word. + +// For example, +// Given words = ["oath","pea","eat","rain"] and board = + +// [ +// ['o','a','a','n'], +// ['e','t','a','e'], +// ['i','h','k','r'], +// ['i','f','l','v'] +// ] +// Return ["eat","oath"]. +// Note: +// You may assume that all inputs are consist of lowercase letters a-z. + +// click to show hint. + +// Hide Company Tags Microsoft Google Airbnb +// Hide Tags Backtracking Trie +// Hide Similar Problems (M) Word Search + + + +/** + * @param {character[][]} board + * @param {string[]} words + * @return {string[]} + */ +var findWords = function(board, words) { + var root = buildTrie(words); + var result = []; + + for(var i = 0; i < board.length; i++) { + for(var j = 0; j < board[0].length; j++) { + searchWord(result, root, board, i, j); + } + } + + return result; +}; + +function searchWord(result, root, board, i, j) { + if(root.word) { + result.push(root.word); + root.word = null; + } + + if(i < 0 || i >= board.length || j < 0 || j >= board[0].length) { + return; + } + + if(board[i][j] === '#' || !root.children[board[i][j]]) { + return; + } + + var ch = board[i][j]; + board[i][j] = '#'; + + searchWord(result, root.children[ch], board, i+1, j); + searchWord(result, root.children[ch], board, i-1, j); + searchWord(result, root.children[ch], board, i, j+1); + searchWord(result, root.children[ch], board, i, j-1) + + board[i][j] = ch; +} + + +function buildTrie(words) { + var root = new TrieNode(); + + for(var i = 0; i < words.length; i++) { + var word = words[i]; + var node = root; + + for(var j = 0; j < word.length; j++) { + var ch = word[j]; + + node.children[ch] = node.children[ch] || new TrieNode(); + node = node.children[ch]; + } + + node.word = word; + } + + return root; +} + +class TrieNode { + constructor() { + this.word = null; + this.children = {}; + } +} \ No newline at end of file diff --git a/213 House Robber II.js b/213 House Robber II.js new file mode 100644 index 0000000..18e1038 --- /dev/null +++ b/213 House Robber II.js @@ -0,0 +1,39 @@ +// Note: This is an extension of House Robber. + +// After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street. + +// Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police. +// Microsoft + + +/** + * @param {number[]} nums + * @return {number} + */ +var rob = function(nums) { + // same as house robber I, but we cannot rob first and last house at the same time. + + function robHouses(nums) { + var odd = 0; + var even = 0; + + for(var i = 0; i < nums.length; i++) { + var num = nums[i]; + if(i % 2 === 0) { + even = Math.max(even + num, odd); + } else { + odd = Math.max(odd + num, even); + } + } + + return Math.max(even, odd); + } + + if(nums.length <= 1) { + return robHouses(nums); + } + + var robHousesExceptLast = robHouses(nums.slice(0, -1)); + var robHousesExceptFirst = robHouses(nums.slice(1)); + return Math.max(robHousesExceptLast, robHousesExceptFirst); +}; \ No newline at end of file diff --git a/215 Kth Largest Element in an Array.js b/215 Kth Largest Element in an Array.js new file mode 100644 index 0000000..c4253a6 --- /dev/null +++ b/215 Kth Largest Element in an Array.js @@ -0,0 +1,50 @@ +// Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element. + +// For example, +// Given [3,2,1,5,6,4] and k = 2, return 5. + +// Note: +// You may assume k is always valid, 1 ≤ k ≤ array's length. + +// Credits: +// Special thanks to @mithmatt for adding this problem and creating all test cases. + +// Hide Company Tags Facebook Amazon Microsoft Apple Bloomberg Pocket Gems +// Hide Tags Heap Divide and Conquer +// Hide Similar Problems (M) Wiggle Sort II (M) Top K Frequent Elements + + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + +// use quick select +var findKthLargest = function(nums, k) { + var smaller = []; + var larger = []; + var pivot = nums[parseInt(nums.length/2)]; + var pivotCnt = 0; + + for(var i = 0; i < nums.length; i++) { + var num = nums[i]; + + if(num > pivot) { + larger.push(num); + } else if(num < pivot) { + smaller.push(num); + } else { + pivotCnt++; + } + } + + if(k <= larger.length) { // if larger includes k + return findKthLargest(larger, k); + } else if(k - larger.length - pivotCnt <= 0) { // k is part of pivot + return pivot; + } else { // if smaller inclues k + return findKthLargest(smaller, k - larger.length - pivotCnt); + } +}; \ No newline at end of file diff --git a/215 Kth Largest Element in an Array.py b/215 Kth Largest Element in an Array.py new file mode 100644 index 0000000..f73c7e9 --- /dev/null +++ b/215 Kth Largest Element in an Array.py @@ -0,0 +1,22 @@ +class Solution(object): + def findKthLargest(self, nums, k): + """ + :type nums: List[int] + :type k: int + :rtype: int + """ + + pivot = random.choice(nums); + nums1, nums2 = [], [] + for num in nums: + if num > pivot: + nums1.append(num) + elif num < pivot: + nums2.append(num) + + if k <= len(nums1): + return self.findKthLargest(nums1, k) + if k > len(nums) - len(nums2): # draw a graph to visualize it! It's not in the top k assortment, but in the small section + return self.findKthLargest(nums2, k - (len(nums) - len(nums2))) + + return pivot \ No newline at end of file diff --git a/221 Maximal Square.js b/221 Maximal Square.js new file mode 100644 index 0000000..7fba62b --- /dev/null +++ b/221 Maximal Square.js @@ -0,0 +1,56 @@ +// Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 1's and return its area. + +// For example, given the following matrix: + +// 1 0 1 0 0 +// 1 0 1 1 1 +// 1 1 1 1 1 +// 1 0 0 1 0 +// Return 4. +// Credits: +// Special thanks to @Freezen for adding this problem and creating all test cases. + +// Hide Company Tags Apple Airbnb Facebook +// Hide Tags Dynamic Programming +// Hide Similar Problems (H) Maximal Rectangle + + +/** + * @param {character[][]} matrix + * @return {number} + */ +var maximalSquare = function(matrix) { + var dp = []; + var ans = 0; + + for(var i = 0; i < matrix.length; i++) { + var arr = Array(matrix[i].length).fill(0); + dp.push(arr); + } + + for(var x = 0; x < matrix.length; x++) { + for(var y = 0; y < matrix[x].length; y++) { + dp[x][y] = parseInt(matrix[x][y]); + + // conditions to make sure that x !== 0 && y !== 0 && dp[x][y] !== 0 + // dp[x][y] is the current position + // if the current position is not 1 then it cannot form square from previous values + // and if matrix[x][y] is 0, then it will next dp[x+1][y+1] becomes zero plus one, since x+1 and y+1 will become the new start of the square. + if(x && y && dp[x][y]) { + dp[x][y] = Math.min(dp[x - 1][y - 1], dp[x - 1][y], dp[x][y - 1]) + 1; + } + + ans = Math.max(ans, dp[x][y]); + } + } + + return Math.pow(ans, 2); +}; + +var matrix = ["1111","1111","1111"]; +// dp becomes +// 1111 +// 1222 +// 1233 + +console.log(maximalSquare(matrix)); \ No newline at end of file diff --git a/222. Count Complete Tree Nodes.js b/222. Count Complete Tree Nodes.js new file mode 100644 index 0000000..3e5fd75 --- /dev/null +++ b/222. Count Complete Tree Nodes.js @@ -0,0 +1,38 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +var countNodes = function(root) { + return treeNodes(root); + + function treeNodes(node){ + if(!node){ + return 0; + }else{ + var leftDepth = 0; + var rightDepth = 0; + var leftChild = node.left; + while(leftChild){ + leftDepth++; + leftChild = leftChild.left; + } + var rightChild = node.right; + while(rightChild){ + rightDepth++; + rightChild = rightChild.right; + } + if(leftDepth === rightDepth){ + return Math.pow(2, leftDepth + 1) - 1; + }else{ + return treeNodes(node.left) + treeNodes(node.right) + 1; + } + } + } +}; \ No newline at end of file diff --git a/224 Basic Calculator.js b/224 Basic Calculator.js new file mode 100644 index 0000000..d5c6a75 --- /dev/null +++ b/224 Basic Calculator.js @@ -0,0 +1,119 @@ +// http://yucoding.blogspot.com/2015/10/leetcode-question-basic-calculator.html +// http://blog.welkinlan.com/2015/09/06/basic-calculator-i-ii-leetcode-java/ + +/** +Implement a basic calculator to evaluate a simple expression string. + +The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces . + +You may assume that the given expression is always valid. + +Some examples: +"1 + 1" = 2 +" 2-1 + 2 " = 3 +"(1+(4+5+2)-3)+(6+8)" = 23 +Note: Do not use the eval built-in library function. +*/ +/** + * @param {string} s + * @return {number} + */ +// var calculate = function(s) { +// var stack = [], +// len = s.length, +// sum = 0, +// num, +// ch, +// j, +// i; + +// stack.push(1); +// stack.push(1); + +// for (i = 0; i < len; i++) { +// ch = s.charAt(i); + +// if (!isNaN(parseInt(ch))) { +// num = parseInt(ch); + +// for (j = i + 1; j < len && !isNaN(parseInt(s.charAt(j))); j++) { +// num = num * 10 + parseInt(s.charAt(j)); +// } + +// sum += stack.pop() * num; + +// i = j - 1; +// } else if (ch === '+' || ch === '(') { +// stack.push(stack[stack.length - 1]); +// } else if (ch === '-') { +// stack.push(stack[stack.length - 1] * (-1)); +// } else if (ch === ')') { +// stack.pop(); +// } +// } + +// return sum; +// }; + + + +/** +Implement a basic calculator to evaluate a simple expression string. + +The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces . + +You may assume that the given expression is always valid. + +Some examples: +"1 + 1" = 2 +" 2-1 + 2 " = 3 +"(1+(4+5+2)-3)+(6+8)" = 23 +Note: Do not use the eval built-in library function. +*/ +/** + * @param {string} s + * @return {number} + */ + + + +console.log(calculate("10+20-((2-4)*6-5)*6")); +var calculate = function(s) { + + + + + +} + +function helper(s, i, sign, finalSum, currentSum) { + while(i < s.length) { + if(s[i].match(/[0-9]/)) { + var num = 0; + + while(i < s.length) { + if(s[i].match(/[0-9]/)) { + num *= 10; + num += parseInt(s[i]); + i++ + } else { + break; + } + } + } else if(s[i] === '-') { + + } else if(s[i] === '+') { + return num + helper(s, i, sign, finalSum, currentSum); + } else if(s[i] === '*') { + + } else if(s[i] === '/') { + + } else if(s[i] === '(') { + + } else if(s[i] === ')') { + + } + + i++; + } +} \ No newline at end of file diff --git a/226 Invert Binary Tree.js b/226 Invert Binary Tree.js index 5f66cd3..14ca813 100644 --- a/226 Invert Binary Tree.js +++ b/226 Invert Binary Tree.js @@ -1,3 +1,23 @@ +// Invert a binary tree. + +// 4 +// / \ +// 2 7 +// / \ / \ +// 1 3 6 9 +// to +// 4 +// / \ +// 7 2 +// / \ / \ +// 9 6 3 1 +// Trivia: +// This problem was inspired by this original tweet by Max Howell: +// Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off. +// Hide Tags Tree + + + // Leetcode #226 // Language: Javascript // Problem: https://leetcode.com/problems/invert-binary-tree/ @@ -14,27 +34,16 @@ * @return {TreeNode} */ var invertTree = function(root) { - var cur = root; - - generate(root); - - return cur; -}; - - -var generate = function(root){ - if(!root){ - return null; - } - - if(root.left === null && root.right === null){ + if(root === null) { return root; } - var temp = root.left; + var tmp = root.left; root.left = root.right; - root.right = temp; - + root.right = tmp; + invertTree(root.left); invertTree(root.right); -} + + return root; +}; \ No newline at end of file diff --git a/23 Merge k Sorted Lists.js b/23 Merge k Sorted Lists.js new file mode 100644 index 0000000..8ee44d1 --- /dev/null +++ b/23 Merge k Sorted Lists.js @@ -0,0 +1,68 @@ +// Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. +// http://www.cnblogs.com/springfor/p/3869217.html + +// Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. + +// Hide Company Tags LinkedIn Google Uber Airbnb Facebook Twitter Amazon Microsoft +// Hide Tags Divide and Conquer Linked List Heap +// Hide Similar Problems (E) Merge Two Sorted Lists (M) Ugly Number II + +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode[]} lists + * @return {ListNode} + */ +var mergeKLists = function(lists) { + + function merge(beg, end, lists) { + if(beg > end) { + return []; + } + + if(beg === end) { + return lists[beg]; + } + + var mid = beg + Math.floor((end - beg)/2); + var left = merge(beg, mid, lists); + var right = merge(mid + 1, end, lists); + + return mergeTwoLists(left, right); + } + + function mergeTwoLists(list1, list2) { + var head = new ListNode(0); + var tmp = head; + + while(list1 && list2) { + if(list1.val < list2.val) { + tmp.next = list1; + list1 = list1.next; + } else { + tmp.next = list2; + list2 = list2.next; + } + + tmp = tmp.next; + } + + if(list1) { + tmp.next = list1; + } else if(list2) { + tmp.next = list2; + } + + tmp = head.next; + head.next = null; + + return tmp; + } + + return merge(0, lists.length - 1, lists); +}; \ No newline at end of file diff --git a/231 Power of Two.js b/231 Power of Two.js index 7b908b6..8426ff4 100644 --- a/231 Power of Two.js +++ b/231 Power of Two.js @@ -2,6 +2,16 @@ // Language: Javascript // Problem: https://leetcode.com/problems/power-of-two/ // Author: Chihung Yu +// Given an integer, write a function to determine if it is a power of two. + +// Credits: +// Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases. + +// Hide Company Tags Google +// Hide Tags Math Bit Manipulation +// Hide Similar Problems (E) Number of 1 Bits (E) Power of Three (E) Power of Four + + /** * @param {number} n * @return {boolean} diff --git a/234 Palindrome Linked List.js b/234 Palindrome Linked List.js index 00b2f1c..d20ef93 100644 --- a/234 Palindrome Linked List.js +++ b/234 Palindrome Linked List.js @@ -26,6 +26,17 @@ var isPalindrome = function(head) { fast = fast.next.next; } + // if fast.next === null it's odd + // else fast.next !== null it's even + // but wether it's odd or even, we want to reverse slow's next + // 1 2 3 3 2 1 + // slow is pointing at 3 (index 2) and we want to reverse 3 2 1 + // to 1 2 3 1 2 3 + // + // 1 2 3 4 3 2 1 + // slow is pointing at 4 (index 3) and we want to reverse 3 2 1 + // to 1 2 3 4 1 2 3 + var secondHead = slow.next; slow.next = null; diff --git a/236 Lowest Common Ancestor of a Binary Tree.js b/236 Lowest Common Ancestor of a Binary Tree.js new file mode 100644 index 0000000..1bd5b77 --- /dev/null +++ b/236 Lowest Common Ancestor of a Binary Tree.js @@ -0,0 +1,71 @@ +// Given a binary tree, find the lowest common ancestor (LCA) of two given nodes in the tree. + +// According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes v and w as the lowest node in T that has both v and w as descendants (where we allow a node to be a descendant of itself).” + +// _______3______ +// / \ +// ___5__ ___1__ +// / \ / \ +// 6 _2 0 8 +// / \ +// 7 4 +// For example, the lowest common ancestor (LCA) of nodes 5 and 1 is 3. Another example is LCA of nodes 5 and 4 is 5, since a node can be a descendant of itself according to the LCA definition. + +// Hide Company Tags Amazon LinkedIn Apple Facebook Microsoft +// Show Tags +// Show Similar Problems + + + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ + +// Amazon LinkedIn Apple Facebook Microsoft +// Hide Tags Tree +// Hide Similar Problems + +// reference: http://www.cnblogs.com/anne-vista/p/4815076.html +var lowestCommonAncestor = function(root, p, q) { + if(root === null || root === p || root === q) { + return root; + } + + var l = lowestCommonAncestor(root.left, p, q); + var r = lowestCommonAncestor(root.right, p, q); + + if(l !== null && r !== null) { + // p and q are on two different side of root node. + return root; + } + + return (l !== null) ? l : r; // either one of p, q is on one side OR p, q is not in l&r subtrees +}; + + +// second attempt + +var lowestCommonAncestor = function(root, p, q) { + if(root === null || root === p || root === q) { + return root; + } + + var left = lowestCommonAncestor(root.left, p, q); + var right = lowestCommonAncestor(root.right, p, q); + + if(left !== null && right !== null) { + return root; + } + + return left || right; +}; \ No newline at end of file diff --git a/238 Product of Array Except Self.js b/238 Product of Array Except Self.js new file mode 100644 index 0000000..ade4c27 --- /dev/null +++ b/238 Product of Array Except Self.js @@ -0,0 +1,30 @@ +// Given an array of n integers where n > 1, nums, return an array output such that output[i] is equal to the product of all the elements of nums except nums[i]. + +// Solve it without division and in O(n). + +// For example, given [1,2,3,4], return [24,12,8,6]. + +// Follow up: +// Could you solve it with constant space complexity? (Note: The output array does not count as extra space for the purpose of space complexity analysis.) + +/** + * @param {number[]} nums + * @return {number[]} + */ + +// http://fisherlei.blogspot.com/2015/10/leetcode-product-of-array-except-self.html +var productExceptSelf = function(nums) { + var len = nums.length; + var output = Array(len).fill(1); + var left = 1; + var right = 1; + + for(var i = 0; i < len - 1; i++) { + left *= nums[i]; + right *= nums[len - i - 1]; + output[i + 1] *= left; + output[len - i - 2] *= right; + } + + return output; +}; \ No newline at end of file diff --git a/239 Sliding Window Maximum.js b/239 Sliding Window Maximum.js new file mode 100644 index 0000000..6458c91 --- /dev/null +++ b/239 Sliding Window Maximum.js @@ -0,0 +1,56 @@ +// Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. + +// For example, +// Given nums = [1,3,-1,-3,5,3,6,7], and k = 3. + +// Window position Max +// --------------- ----- +// [1 3 -1] -3 5 3 6 7 3 +// 1 [3 -1 -3] 5 3 6 7 3 +// 1 3 [-1 -3 5] 3 6 7 5 +// 1 3 -1 [-3 5 3] 6 7 5 +// 1 3 -1 -3 [5 3 6] 7 6 +// 1 3 -1 -3 5 [3 6 7] 7 +// Therefore, return the max sliding window as [3,3,5,5,6,7]. + +/** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ +var maxSlidingWindow = function(nums, k) { + var result = [], + linkedListWithTwoEndsOps = [], + len = nums.length, + i; + + if (k > len || k === 0) { + return result; + } + + for (i = 0; i < len; i++) { + // Remove anything that is less than the current value + // so linkedListWithTwoEndsOps maintains values greater than the curret value + while (linkedListWithTwoEndsOps.length > 0 && nums[linkedListWithTwoEndsOps[linkedListWithTwoEndsOps.length - 1]] < nums[i]) { + var val = linkedListWithTwoEndsOps.pop(); + } + + // In case that all elements in the linkedListWithTwoEndsOps are all greater than the current one (descending order) + // Shift out the + if (linkedListWithTwoEndsOps[0] < i - k + 1) { + linkedListWithTwoEndsOps.shift(); + } + + linkedListWithTwoEndsOps.push(i); + + // For each sliding window movement, we record the highest value in that sliding window + // i >= k - 1 to ensure that we don't prematurely record values before we get to the full range of the first sliding window + // e.g. [1 3 -1] -3 5 3 6 7 3 + // this ensure that i is at least at -1 (index 2) + if (i >= k - 1) { + result.push(nums[linkedListWithTwoEndsOps[0]]); + } + } + + return result; +}; \ No newline at end of file diff --git a/242 Valid Anagram.js b/242 Valid Anagram.js index 5b749e6..151c4c0 100644 --- a/242 Valid Anagram.js +++ b/242 Valid Anagram.js @@ -1,30 +1,79 @@ -// Leetcode #242 -// Language: Javascript -// Problem: https://leetcode.com/problems/valid-anagram/ -// Author: Chihung Yu +// Given two strings s and t, write a function to determine if t is an anagram of s. + +// For example, +// s = "anagram", t = "nagaram", return true. +// s = "rat", t = "car", return false. + + + /** * @param {string} s * @param {string} t * @return {boolean} */ var isAnagram = function(s, t) { - if((s === null || t === null) || (s.length !== t.length)){ + var slen = s.length; + var tlen = t.length; + + if(slen !== tlen) { + return false; + } + + var hash = {}; + + for(var i = 0; i < slen; i++) { + var char = s[i]; + hash[char] = hash[char] || 0; + hash[char]++; + } + + for(i = 0; i < tlen; i++) { + char = t[i]; + + if(hash[char] === undefined || hash[char] === 0) { + return false; + } + + hash[char]--; + } + + return true; +}; + + + + +/** + * @param {string} s + * @param {string} t + * @return {boolean} + */ +var isAnagram = function(s, t) { + if (s === null || t === null || s.length !== t.length) { return false; } var hash = {}; - - for(var i = 0; i < s.length; i++){ - hash[s[i]] = hash[s[i]] || 0; - hash[s[i]]++; + var i; + for(i = 0; i < s.length; i++) { + var sval = s[i]; + var tval = t[i]; + + if (hash[sval] === undefined) { + hash[sval] = 0; + } + + if (hash[tval] === undefined) { + hash[tval] = 0; + } + hash[sval]++; + hash[tval]--; } - for(var j = 0; j < t.length; j++){ - if(!hash[t[j]]){ + for(var j in hash) { + if (hash[j] !== 0) { return false; } - - hash[t[j]]--; } return true; diff --git a/243 Shortest Word Distance.js b/243 Shortest Word Distance.js new file mode 100644 index 0000000..98e3af8 --- /dev/null +++ b/243 Shortest Word Distance.js @@ -0,0 +1,34 @@ +// Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list. + +// For example, +// Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + +// Given word1 = “coding”, word2 = “practice”, return 3. +// Given word1 = "makes", word2 = "coding", return 1. + +// Note: +// You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. + +// Hide Company Tags LinkedIn +// Hide Tags + + +var shortestDistance = function(words, word1, word2) { + var idx1 = -1; + var idx2 = -1; + var dist = words.length - 1; + + for(var i = 0; i < words.length; i++) { + if(words[i] === word1) { + idx1 = i; + } else if(words[i] === word2) { + idx2 = i; + } + + if(idx1 !== -1 && idx2 !== -1) { + dist = Math.min(dist, Math.abs(idx1 - idx2)) + } + } + + return dist; +}; \ No newline at end of file diff --git a/244 Shortest Word Distance II.js b/244 Shortest Word Distance II.js new file mode 100644 index 0000000..3c7eee7 --- /dev/null +++ b/244 Shortest Word Distance II.js @@ -0,0 +1,67 @@ +// This is a follow up of Shortest Word Distance. The only difference is now you are given the list of words and your method will be called repeatedly many times with different parameters. How would you optimize it? + +// Design a class which receives a list of words in the constructor, and implements a method that takes two words word1 and word2 and return the shortest distance between these two words in the list. + +// For example, +// Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + +// Given word1 = “coding”, word2 = “practice”, return 3. +// Given word1 = "makes", word2 = "coding", return 1. + +// Note: +// You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. + +// Hide Company Tags LinkedIn +// Hide Tags Hash Table Design +// Show Similar Problems + + +/** + * @constructor + * @param {string[]} words + */ +var WordDistance = function(words) { + this.positions = {}; + + for(var i = 0; i < words.length; i++) { + var word = words[i]; + + this.positions[word] = this.positions[word] || []; + this.positions[word].push(i); + } +}; + +/** + * @param {string} word1 + * @param {string} word2 + * @return {integer} + */ +WordDistance.prototype.shortest = function(word1, word2) { + var i = 0; + var j = 0; + var dist = Infinity; + var pos1 = this.positions[word1]; + var pos2 = this.positions[word2]; + + while(i < pos1.length && j < pos2.length) { + var i1 = pos1[i]; + var i2 = pos2[j]; + + dist = Math.min(dist, Math.abs(i1 - i2)); + + if(i1 < i2) { + i++; + } else { + j++; + } + } + + return dist; +}; + +/** + * Your WordDistance object will be instantiated and called as such: + * var wordDistance = new WordDistance(words); + * wordDistance.shortest("word1", "word2"); + * wordDistance.shortest("anotherWord1", "anotherWord2"); + */ \ No newline at end of file diff --git a/245 Shortest Word Distance III.js b/245 Shortest Word Distance III.js new file mode 100644 index 0000000..a5a2c20 --- /dev/null +++ b/245 Shortest Word Distance III.js @@ -0,0 +1,49 @@ +// This is a follow up of Shortest Word Distance. The only difference is now word1 could be the same as word2. + +// Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list. + +// word1 and word2 may be the same and they represent two individual words in the list. + +// For example, +// Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + +// Given word1 = “makes”, word2 = “coding”, return 1. +// Given word1 = "makes", word2 = "makes", return 3. + +// Note: +// You may assume word1 and word2 are both in the list. + +// Hide Company Tags LinkedIn +// Hide Tags Array +// Hide Similar Problems + + +/** + * @param {string[]} words + * @param {string} word1 + * @param {string} word2 + * @return {number} + */ +var shortestWordDistance = function(words, word1, word2) { + var idx1 = -1; + var idx2 = -1; + var dist = words.length - 1; + + for(var i = 0; i < words.length; i++) { + if(words[i] === word1) { + if(words[idx1] === word1 && word1 === word2) { + idx2 = idx1; + } + + idx1 = i; + } else if(words[i] === word2) { + idx2 = i; + } + + if(idx1 !== -1 && idx2 !== -1) { + dist = Math.min(dist, Math.abs(idx1 - idx2)) + } + } + + return dist; +}; \ No newline at end of file diff --git a/249 Group Shifted Strings.js b/249 Group Shifted Strings.js new file mode 100644 index 0000000..198a39d --- /dev/null +++ b/249 Group Shifted Strings.js @@ -0,0 +1,45 @@ +// 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: + +// "abc" -> "bcd" -> ... -> "xyz" +// Given a list of strings which contains only lowercase alphabets, group all strings that belong to the same shifting sequence. + +// For example, given: ["abc", "bcd", "acef", "xyz", "az", "ba", "a", "z"], +// A solution is: + +// [ +// ["abc","bcd","xyz"], +// ["az","ba"], +// ["acef"], +// ["a","z"] +// ] +// reference: http://blog.csdn.net/pointbreak1/article/details/48780345 + +/** + * @param {string[]} strings + * @return {string[][]} + */ +var groupStrings = function(strings) { + var result = []; + var map = new Map(); + + for(var i = 0; i < strings.length; i++) { + var shift = ''; + var string = strings[i] + for(var j = 0; j < string.length; j++) { + shift += (string.charCodeAt(j) - string.charCodeAt(0) + 26)%26; + shift += ' '; + } + if(map.has(shift)) { + map.get(shift).push(string); + } else { + map.set(shift, [string]); + } + } + + map.forEach((value, key)=> { + result.push(value); + }); + + + return result; +}; \ No newline at end of file diff --git a/25 Reverse Nodes in k-Group.js b/25 Reverse Nodes in k-Group.js new file mode 100644 index 0000000..bd0fabc --- /dev/null +++ b/25 Reverse Nodes in k-Group.js @@ -0,0 +1,64 @@ + +// Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. + +// If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is. + +// You may not alter the values in the nodes, only nodes itself may be changed. + +// Only constant memory is allowed. + +// For example, +// Given this linked list: 1->2->3->4->5 + +// For k = 2, you should return: 2->1->4->3->5 + +// For k = 3, you should return: 3->2->1->4->5 + + +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + + // http://www.geeksforgeeks.org/reverse-a-list-in-groups-of-given-size/ +var reverseKGroup = function(head, k) { + var cur = head; + var pre = null; + var post = null; + var count = 0; + + while(cur !== null && count < k) { + cur = cur.next; + count++; + } + + if(count !== k) { + return head; + } + + cur = head; + + while(cur !== null && count > 0) { + post = cur.next; + cur.next = pre; + pre = cur; + cur = post; + count--; + } + + // post is now a pointer to (k+1)th node + // recursively call for the list starting from cur + if(post !== null) { + head.next = reverseKGroup(post, k); + } + + return pre; +}; \ No newline at end of file diff --git a/252 Meeting Rooms.js b/252 Meeting Rooms.js new file mode 100644 index 0000000..4740965 --- /dev/null +++ b/252 Meeting Rooms.js @@ -0,0 +1,57 @@ +// Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), determine if a person could attend all meetings. + +// For example, +// Given [[0, 30],[5, 10],[15, 20]], +// return false. + +// Hide Company Tags Facebook +// Hide Tags Sort +// Hide Similar Problems (H) Merge Intervals (M) Meeting Rooms II + + +/** + * Definition for an interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * } + */ +/** + * @param {Interval[]} intervals + * @return {boolean} + */ + +// 132 ms +var canAttendMeetings = function(intervals) { + // sort by starting time + intervals.sort((interval1, interval2)=> interval1.start > interval2.start ? 1 : -1); + + for(var i = 1; i < intervals.length; i++) { + var pre = intervals[i-1]; + var cur = intervals[i]; + + if(pre.end > cur.start) { + return false; + } + } + + return true; +}; + + + +// second attempt + +var canAttendMeetings = function(intervals) { + intervals.sort((a,b) => { + return a.start > b.start ? 1 : -1; + }); + + for(var i = 1; i < intervals.length; i++) { + if(intervals[i - 1].end > intervals[i].start) { + return false; + } + } + + return true; +}; \ No newline at end of file diff --git a/253 Meeting Rooms II.js b/253 Meeting Rooms II.js new file mode 100644 index 0000000..8cddac0 --- /dev/null +++ b/253 Meeting Rooms II.js @@ -0,0 +1,54 @@ +// Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), +// find the minimum number of conference rooms required. + +// For example, +// Given [[0, 30],[5, 10],[15, 20]], +// return 2. + +// Hide Company Tags Google Facebook +// Hide Tags Heap Greedy Sort +// Hide Similar Problems (H) Merge Intervals (E) Meeting Rooms + + +/** + * Definition for an interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * } + */ +/** + * @param {Interval[]} intervals + * @return {number} + */ + +var minMeetingRooms = function(intervals) { + var schedule = {}; + + intervals.forEach((interval)=>{ + schedule[interval.start] = schedule[interval.start] || 0; + schedule[interval.start]++; + + schedule[interval.end] = schedule[interval.end] || 0; + schedule[interval.end]--; + }); + + var maxRooms = 0; + var rooms = 0; + + for(var i in schedule) { + rooms += schedule[i]; + maxRooms = Math.max(maxRooms, rooms); + } + + return maxRooms; +}; + +var data = [ + {start: 9, end: 12}, + {start: 2, end: 7}, + {start: 5, end: 17}, + {start: 12, end: 17}, +] + +console.log(minMeetingRooms(data)); \ No newline at end of file diff --git a/254 Factor Combinations.js b/254 Factor Combinations.js new file mode 100644 index 0000000..58ac238 --- /dev/null +++ b/254 Factor Combinations.js @@ -0,0 +1,68 @@ +// Numbers can be regarded as product of its factors. For example, + +// 8 = 2 x 2 x 2; +// = 2 x 4. +// Write a function that takes an integer n and return all possible combinations of its factors. + +// Note: +// You may assume that n is always positive. +// Factors should be greater than 1 and less than n. +// Examples: +// input: 1 +// output: +// [] +// input: 37 +// output: +// [] +// input: 12 +// output: +// [ +// [2, 6], +// [2, 2, 3], +// [3, 4] +// ] +// input: 32 +// output: +// [ +// [2, 16], +// [2, 2, 8], +// [2, 2, 2, 4], +// [2, 2, 2, 2, 2], +// [2, 4, 4], +// [4, 8] +// ] +// Hide Company Tags LinkedIn Uber +// Hide Tags Backtracking +// Show Similar Problems + + +/** + * @param {number} n + * @return {number[][]} + */ + +// reference: http://www.cnblogs.com/airwindow/p/4822572.html +var getFactors = function(n) { + var result = []; + gatherResult(n, 2, [], result); + return result; +}; + +function gatherResult(n, start, currentResult, finalResult) { + if(n === 1) { + if(currentResult.length > 1) { + finalResult.push(currentResult.slice()); + } + + return; + } + // i = start will ensure ascending order + for(var i = start; i <= n; i++) { + if(n%i === 0) { + currentResult.push(i); + gatherResult(n/i, i, currentResult, finalResult); + currentResult.pop(); + } + } +} + \ No newline at end of file diff --git a/256 Paint House.js b/256 Paint House.js new file mode 100644 index 0000000..08e1140 --- /dev/null +++ b/256 Paint House.js @@ -0,0 +1,34 @@ +// There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color. + +// The cost of painting each house with a certain color is represented by a n x 3 cost matrix. For example, costs[0][0] is the cost of painting house 0 with color red; costs[1][2] is the cost of painting house 1 with color green, and so on... Find the minimum cost to paint all houses. + +// Note: +// All costs are positive integers. + +// Hide Company Tags LinkedIn +// Show Tags +// Show Similar Problems + +// reference: https://segmentfault.com/a/1190000003903965 +/** + * @param {number[][]} costs + * @return {number} + */ + + // space O(1) time O(n) +var minCost = function(costs) { + if(!costs || costs.length === 0) { + return 0; + } + + for(var i = 1; i < costs.length; i++) { + // The colors that can be painted depends on the color we used for the previous houses, + // pick the min cost from previous colors + costs[i][0] += Math.min(costs[i-1][1], costs[i-1][2]); + costs[i][1] += Math.min(costs[i-1][0], costs[i-1][2]); + costs[i][2] += Math.min(costs[i-1][0], costs[i-1][1]); + } + + i--; + return Math.min.apply(null, costs[i]); +}; \ No newline at end of file diff --git a/257 Binary Tree Paths.js b/257 Binary Tree Paths.js new file mode 100644 index 0000000..7f7dce5 --- /dev/null +++ b/257 Binary Tree Paths.js @@ -0,0 +1,55 @@ +// Given a binary tree, return all root-to-leaf paths. + +// For example, given the following binary tree: + +// 1 +// / \ +// 2 3 +// \ +// 5 +// All root-to-leaf paths are: + +// ["1->2->5", "1->3"] +// Credits: +// Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases. + +// Hide Company Tags Google Apple Facebook +// Hide Tags Tree Depth-first Search +// Hide Similar Problems (M) Path Sum II + + /** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ + /** + * @param {TreeNode} root + * @return {string[]} + */ + + var binaryTreePaths = function(root) { + var res = []; + + function dfs(node, curr, res) { + if(node === null) { + return; + } + + curr.push(node.val); + + if(node.left === null && node.right === null) { + res.push(curr.join('->')); + } else { + dfs(node.left, curr, res); + dfs(node.right, curr, res); + } + + curr.pop(); + } + + dfs(root, [], res); + + return res; + }; \ No newline at end of file diff --git a/26 Remove Duplicates from Sorted Array.js b/26 Remove Duplicates from Sorted Array.js index 33ee2cd..04f251e 100644 --- a/26 Remove Duplicates from Sorted Array.js +++ b/26 Remove Duplicates from Sorted Array.js @@ -1,21 +1,82 @@ +// Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. + +// Do not allocate extra space for another array, you must do this in place with constant memory. + +// For example, +// Given input array nums = [1,1,2], + +// Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the new length. + + /** - * @param {number[]} A + * @param {number[]} nums * @return {number} */ -var removeDuplicates = function(A) { - if(A === null){ +var removeDuplicates = function(nums) { + if(!nums || nums.length === 0) { return 0; } + + var end = 0; - var index = 1; + // index: 012345678 + // vals: 111222333 + // first swap happen when end = 0; i points at index 3 with val 2 + // end++ becomes end points at index 1 and swap with index 3 + // after that vals become: + // vals: 121122333 + // i at at index 4 and end is at index 2 - while(index < A.length){ - if(A[index] === A[index - 1]){ - A.splice(index, 1); - } else{ - index++; + for(var i = 1; i < nums.length; i++) { + if(nums[i] !== nums[end]) { + end++; + + if(i !== end) { + nums[end] = nums[i]; + } } } - return A.length; + return end+1; +}; + + + +// second attempt + +var removeDuplicates = function(nums) { + var sorted = 0; + + for(var i = 1; i < nums.length; i++) { + if(nums[i] !== nums[sorted]) { + sorted++; + nums[sorted] = nums[i]; + } + } + + return sorted + 1; +}; + + +// [tricky] + +/** + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function(nums) { + var hash = {}; + var cur = 0; + + for(var i = 0; i < nums.length; i++) { + var num = nums[i]; + + if (hash[num] === undefined) { + hash[num] = true; + nums[cur] = num; + cur++; + } + } + + return cur; }; \ No newline at end of file diff --git a/260. Single Number III.js b/260. Single Number III.js new file mode 100644 index 0000000..14a4a8c --- /dev/null +++ b/260. Single Number III.js @@ -0,0 +1,34 @@ +/** + * @param {number[]} nums + * @return {number[]} + */ +var singleNumber = function(nums) { + if(nums === null || nums.length <= 2) { + return nums; + } + + var xor = nums[0]; + for(var i = 1; i < nums.length; i++) { + xor ^= nums[i]; + } + + var exp = 1; + while(!(exp & xor)) { + exp = exp * 2; + } + console.log(exp); + var xorBit0 = 0; + var xorBit1 = 0; + + for(var j = 0; j < nums.length; j++) { + if(exp & nums[j]){ + xorBit1 ^= nums[j]; + console.log("with 1: " + nums[j]); + } else { + console.log("with 0: " + nums[j]); + xorBit0 ^= nums[j]; + } + } + + return [xorBit0, xorBit1]; +}; diff --git a/261 Graph Valid Tree.js b/261 Graph Valid Tree.js new file mode 100644 index 0000000..6b920e0 --- /dev/null +++ b/261 Graph Valid Tree.js @@ -0,0 +1,134 @@ +// Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of nodes), write a function to check whether these edges make up a valid tree. + +// For example: + +// Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true. + +// Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false. + +// Show Hint +// Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0, 1] is the same as [1, 0] and thus will not appear together in edges. + +// Hide Company Tags Google Facebook Zenefits +// Hide Tags Depth-first Search Breadth-first Search Graph Union Find +// Hide Similar Problems (M) Course Schedule (M) Number of Connected Components in an Undirected Graph + + +/** + * @param {number} n + * @param {number[][]} edges + * @return {boolean} + */ + + +// reference: https://segmentfault.com/a/1190000003791051 + +var validTree = function(n, edges) { + var unionFind = new UnionFind(n); + + for(var i = 0; i < edges.length; i++) { + if(!unionFind.union(edges[i][0], edges[i][1])) { + return false; + } + } + + return unionFind.count() === 1; +}; + +// reference: http://blog.csdn.net/dm_vincent/article/details/7655764 +class UnionFind { + constructor(size) { + this.ids = []; + + for(var i = 0; i < size; i++) { + this.ids[i] = i; + } + + this.count = size; + } + + union(m, n) { + var src = this.find(m); + var dest = this.find(n); + + if(src === dest) { + return false; + } + + for(var i = 0; i < this.ids.length; i++) { + if(this.ids[i] === src) { + this.ids[i] = dest; + } + } + + // once union, count-- -> count === 1 means it's a tree with no circle + this.count--; + + return true; + } + + find(m) { + return this.ids[m]; + } + + areConnected(m, n) { + return this.find(m) === this.find(n); + } + + count() { + return this.count; + } +} + + + + + + +// second attempt + +var validTree = function(n, edges) { + var unions = []; + for(var i = 0; i < n; i++) { + unions.push(i); + } + + for(i = 0; i < edges.length; i++) { + var edge = edges[i]; + if(isConnected(unions, edge[1], edge[0])) { + return false; + } + } + + var visited = {}; + var diff = 0; + + for(i = 0; i < unions.length; i++) { + var union = unions[i]; + if(visited[union]) { + continue; + } + + visited[union] = true; + diff++; + } + + return diff === 1; +}; + +function isConnected(unions, i, j) { + var group1 = unions[i]; + var group2 = unions[j]; + + if(group1 === group2) { + return true + } + + for(var k = 0; k < unions.length; k++) { + if(unions[k] === group2) { + unions[k] = group1; + } + } + + return false; +} diff --git a/263 Ugly Number.js b/263 Ugly Number.js new file mode 100644 index 0000000..dc66c4f --- /dev/null +++ b/263 Ugly Number.js @@ -0,0 +1,27 @@ +// 263. Ugly Number + +// Write a program to check whether a given number is an ugly number. + +// Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7. + +// Note that 1 is typically treated as an ugly number. + +/** + * @param {number} num + * @return {boolean} + */ +var isUgly = function(num) { + while(num >= 2) { + if(num%2 === 0) { + num /= 2; + } else if(num%3 === 0) { + num /= 3; + } else if(num%5 === 0) { + num /= 5; + } else { + return false; + } + } + + return num === 1; +}; \ No newline at end of file diff --git a/264 Ugly Number II.js b/264 Ugly Number II.js new file mode 100644 index 0000000..56a8491 --- /dev/null +++ b/264 Ugly Number II.js @@ -0,0 +1,41 @@ +// 264. Ugly Number II + +// Write a program to find the n-th ugly number. + +// Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers. + +// Note that 1 is typically treated as an ugly number. + +/** + * @param {number} n + * @return {number} + */ +var nthUglyNumber = function(n) { + var uglys = [1]; + var p2 = 0; + var p3 = 0; + var p5 = 0; + + while(uglys.length < n) { + var ugly2 = uglys[p2]*2; + var ugly3 = uglys[p3]*3; + var ugly5 = uglys[p5]*5; + + var minV = Math.min(ugly2, ugly3, ugly5); + + if(minV === ugly2) { + p2++; + } + if(minV === ugly3) { + p3++; + } + if(minV === ugly5) { + p5++; + } + if(minV !== uglys[uglys.length - 1]) { + uglys.push(minV); + } + } + + return uglys[n-1]; +}; \ No newline at end of file diff --git a/265 Paint House II.js b/265 Paint House II.js new file mode 100644 index 0000000..fcb4a96 --- /dev/null +++ b/265 Paint House II.js @@ -0,0 +1,66 @@ +// There are a row of n houses, each house can be painted with one of the k colors. +// The cost of painting each house with a certain color is different. +// You have to paint all the houses such that no two adjacent houses have the same color. + +// The cost of painting each house with a certain color is represented by a n x k cost matrix. +// For example, costs[0][0] is the cost of painting house 0 with color 0; +// costs[1][2] is the cost of painting house 1 with color 2, and so on... Find the minimum cost to paint all houses. + +// Note: +// All costs are positive integers. + +// Follow up: +// Could you solve it in O(nk) runtime? + +// Hide Company Tags Facebook +// Show Tags +// Show Similar Problems + +/** + * @param {number[][]} costs + * @return {number} + */ + +// reference https://segmentfault.com/a/1190000003903965 +var minCostII = function(costs) { + if(costs === null || costs.length === 0) { + return 0; + } + + var min1Idx = -1; + var min1 = 0; + var min2 = 0; + + for(var i = 0; i < costs.length; i++) { + // min1 and min2 for recording the smallest and the second smallest + // The min cost of using the current paint k: + // is equal to: the min cost of previous paint j (k !== j) + // In order to find the min cost which k !== j, we can use 2 variable min1 and min2 + + var oldMin1Idx = min1Idx; + var oldMin1 = min1; + var oldMin2 = min2; + + min1Idx = -1; + min1 = Infinity; + min2 = Infinity; + + for(var j = 0; j < costs[i].length; j++) { + if(j === oldMin1Idx) { + costs[i][j] += oldMin2; + } else { + costs[i][j] += oldMin1; + } + + if(costs[i][j] < min1) { + min2 = min1; + min1 = costs[i][j]; + min1Idx = j; + } else if(costs[i][j] < min2) { + min2 = costs[i][j]; + } + } + } + + return min1; +}; \ No newline at end of file diff --git a/266 Palindrome Permutation.js b/266 Palindrome Permutation.js new file mode 100644 index 0000000..1a41d7c --- /dev/null +++ b/266 Palindrome Permutation.js @@ -0,0 +1,42 @@ +// Given a string, determine if a permutation of the string could form a palindrome. + +// For example, +// "code" -> False, "aab" -> True, "carerac" -> True. + + +/** + * @param {string} s + * @return {boolean} + */ +var canPermutePalindrome = function(s) { + var countMap = {}; + + for(var i = 0; i < s.length; i++) { + var c = s[i]; + + countMap[c] = countMap[c] || 0; + countMap[c]++; + } + var oddCount = 0; + + for(i in countMap) { + if(countMap[i]%2 === 1) { + oddCount++; + } + } + + return oddCount < 2; +}; + +// Solution (2) that assume it's ascii 256 chars only + +var canPermutePalindrome = function(s) { + // assume that s is only contact 256 english letters + var letters = Array(256).fill(0); + var odd = 0; + for(var i = 0; i < s.length; i++) { + var letterIndex = s[i].charCodeAt(0); + odd += (++letters[letterIndex] & 1) === 1 ? 1 : -1; + } + return odd < 2; +}; \ No newline at end of file diff --git a/269 Alien Dictionary.js b/269 Alien Dictionary.js new file mode 100644 index 0000000..6081235 --- /dev/null +++ b/269 Alien Dictionary.js @@ -0,0 +1,130 @@ +// There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language. + +// For example, +// Given the following words in dictionary, + +// [ +// "wrt", +// "wrf", +// "er", +// "ett", +// "rftt" +// ] +// The correct order is: "wertf". + +// Note: +// You may assume all letters are in lowercase. +// If the order is invalid, return an empty string. +// There may be multiple valid order of letters, return any one of them is fine. +// Hide Company Tags Google Airbnb Facebook Twitter Snapchat Pocket Gems +// Hide Tags Graph Topological Sort +// Hide Similar Problems (M) Course Schedule II + +/** + * @param {string[]} words + * @return {string} + */ +var alienOrder = function(words) { + if (words.length === 0) { + return ''; + } + + const len = words.length; + let requiredCharMap = {}; // value is the prerequisite of key + let charPreReqCount = {}; + let i; + let queue = []; + let result = []; + let hasCycle = false; + + for (i = 0; i < len; i++) { + // wert and woo + // requiredCharMap : { w: [], e: [ 'o' ], r: [], t: [], o: [] } + // charPreReqCount : { w: 0, e: 0, r: 0, t: 0, o: 1 } + const chars = words[i].split(''); + + let j = 0; + + for (j = 0; j < chars.length; j++) { + if (!requiredCharMap[chars[j]]) { + requiredCharMap[chars[j]] = []; + charPreReqCount[chars[j]] = 0; + } + } + + // skip the first one || the same word + if (i === 0 || words[i] === words[i - 1]) { + continue; + } + + const cur = words[i]; + const prev = words[i - 1]; + j = 0; + + + // skip same words such as wert and woo will skip w and compare only ert vs oo + while(j < cur.length && j < prev.length && cur.charAt(j) === prev.charAt(j)) { + j++; + } + + + // since words are in lexico order. wert and woo after skipping w, they becomes ert and oo, e will have higher order than oo + if (j < prev.length && requiredCharMap[prev.charAt(j)].indexOf(cur.charAt(j)) === -1) { + requiredCharMap[prev.charAt(j)].push(cur.charAt(j)); + // number of prerequisite for using that char in this case it will be o: 1 since o has prerequisite e + // { w: [], e: [ 'o' ], r: [], t: [], o: [] } + // { w: 0, e: 0, r: 0, t: 0, o: 1 } + charPreReqCount[cur.charAt(j)]++; + } + } + + + // these will be the roots since there are no prerequisite needed to use them + Object.keys(charPreReqCount).forEach(char => { + if (charPreReqCount[char] === 0) { + queue.push(char); + } + }); + + // for those that we know are root + while(queue.length > 0) { + const rootChar = queue.shift(); + + result.push(rootChar); + + for (i = 0; i < requiredCharMap[rootChar].length; i++) { + var charRequiresRoot = requiredCharMap[rootChar][i]; + charPreReqCount[charRequiresRoot]--; + + if (charPreReqCount[charRequiresRoot] === 0) { + queue.push(charRequiresRoot); + } + } + } + + Object.keys(charPreReqCount).forEach((char) => { + if (charPreReqCount[char] !== 0) { + hasCycle = true; + } + }); + + return hasCycle ? '' : result.join(''); +} + + + +// var words = [ +// "wrt", +// "wrf", +// "er", +// "ett", +// "rftt" +// ]; + + +var words =[ + 'wert', + 'woo' +]; + +console.log('ans', alienOrder(words)); \ No newline at end of file diff --git a/277 Find the Celebrity.js b/277 Find the Celebrity.js new file mode 100644 index 0000000..fd5e23b --- /dev/null +++ b/277 Find the Celebrity.js @@ -0,0 +1,59 @@ +// Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them. + +// Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do is to ask questions like: "Hi, A. Do you know B?" to get information of whether A knows B. You need to find out the celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense). + +// You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a function int findCelebrity(n), your function should minimize the number of calls to knows. + +// Note: There will be exactly one celebrity if he/she is in the party. Return the celebrity's label if there is a celebrity in the party. If there is no celebrity, return -1. + +// Hide Company Tags LinkedIn Facebook +// Show Tags + + + +/** + * Definition for knows() + * + * @param {integer} person a + * @param {integer} person b + * @return {boolean} whether a knows b + * knows = function(a, b) { + * ... + * }; + */ + +/** + * @param {function} knows() + * @return {function} + */ +var solution = function(knows) { + /** + * @param {integer} n Total people + * @return {integer} The celebrity + */ + return function(n) { + var candidate = 0; + + // iterate through the list, + // if candidate is known by i -> continue + // if i doesnt know candidate, i becomes the candidate + for(var i = 1; i < n; i++) { + if(!knows(i, candidate)) { + candidate = i; + } + } + + for(i = 0; i < n; i++) { + if(i === candidate) { + continue; + } + + // if candidate is not known by i or candidate know i + if(!knows(i, candidate) || knows(candidate, i)) { + return -1; + } + } + + return candidate; + }; +}; \ No newline at end of file diff --git a/278 First Bad Version.js b/278 First Bad Version.js new file mode 100644 index 0000000..bdccb14 --- /dev/null +++ b/278 First Bad Version.js @@ -0,0 +1,91 @@ +// You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad. + +// Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad. + +// You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API. + +// Credits: +// Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases. + +// Hide Company Tags Facebook +// Hide Tags Binary Search +// Hide Similar Problems (M) Search for a Range (M) Search Insert Position (E) Guess Number Higher or Lower + + +/** + * Definition for isBadVersion() + * + * @param {integer} version number + * @return {boolean} whether the version is bad + * isBadVersion = function(version) { + * ... + * }; + */ + +/** + * @param {function} isBadVersion() + * @return {function} + */ +var solution = function(isBadVersion) { + /** + * @param {integer} n Total versions + * @return {integer} The first bad version + */ + return function(n) { + var beg = 0; + var end = n; + var lastBad; + + while(beg <= end) { + var mid = beg + Math.floor((end - beg)/2); + if(isBadVersion(mid)) { + // everything including and after are bad version + lastBad = mid; + end = mid - 1; + } else { + beg = mid + 1; + } + } + + return lastBad; + }; +}; + + + +/** + * Definition for isBadVersion() + * + * @param {integer} version number + * @return {boolean} whether the version is bad + * isBadVersion = function(version) { + * ... + * }; + */ + +/** + * @param {function} isBadVersion() + * @return {function} + */ +var solution = function(isBadVersion) { + /** + * @param {integer} n Total versions + * @return {integer} The first bad version + */ + return function(n) { + var left = 1; + var right = n; + + while (left < right) { + var mid = left + Math.floor((right - left)/2); + + if (isBadVersion(mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + }; +}; diff --git a/282 Expression Add Operators.js b/282 Expression Add Operators.js new file mode 100644 index 0000000..5c8572d --- /dev/null +++ b/282 Expression Add Operators.js @@ -0,0 +1,56 @@ +// Given a string that contains only digits 0-9 and a target value, return all possibilities to add binary operators (not unary) +, -, or * between the digits so they evaluate to the target value. + +// Examples: +// "123", 6 -> ["1+2+3", "1*2*3"] +// "232", 8 -> ["2*3+2", "2+3*2"] +// "105", 5 -> ["1*0+5","10-5"] +// "00", 0 -> ["0+0", "0-0", "0*0"] +// "3456237490", 9191 -> [] +// Credits: +// Special thanks to @davidtan1890 for adding this problem and creating all test cases. + +// Hide Company Tags Google Facebook +// Hide Tags Divide and Conquer +// Hide Similar Problems (M) Evaluate Reverse Polish Notation (H) Basic Calculator (M) Basic Calculator II (M) Different Ways to Add Parentheses + + +// reference: http://blog.csdn.net/pointbreak1/article/details/48596115 + +var addOperators = function(num, target) { + function opRecur(num, target, lastOp, result, expression, results) { + if(num.length === 0) { + if(target === result) { + results.push(expression); + } + return; + } + + for(var i = 1; i <= num.length; i++) { + var curr = num.substring(0, i); + if(curr.length > 1 && curr[0] === '0') { + continue; + } + + var rest = num.substring(i); + var currVal = parseInt(curr); + + if(expression.length === 0) { + opRecur(rest, target, currVal, currVal, expression + curr, results); + } else { + opRecur(rest, target, currVal, result + currVal, expression + "+" + curr, results); + opRecur(rest, target,-currVal, result - currVal, expression + "-" + curr, results); + opRecur(rest, target, currVal * lastOp, result - lastOp + lastOp * currVal, expression + "*" + curr, results); + // need to record the last oprand for handling mulitiplication. + // result - lastOP + lastOP * curVaule + // e.g 4+3*2 when dealing with *2, we have 4+3 then -3 then do 3*2 + // The operation for the function will look like 4 + 3 - 3 + 3 * 2 + } + } + } + + var results = []; + opRecur(num, target, 0, 0, '', results); + return results; +}; + +console.log(addOperators('01023', 3)); \ No newline at end of file diff --git a/283 Move Zeroes.js b/283 Move Zeroes.js new file mode 100644 index 0000000..48696ef --- /dev/null +++ b/283 Move Zeroes.js @@ -0,0 +1,64 @@ +// Given an array nums, write a function to move all 0's to the end of it while maintaining the relative order of the non-zero elements. + +// For example, given nums = [0, 1, 0, 3, 12], after calling your function, nums should be [1, 3, 12, 0, 0]. + +// Note: +// You must do this in-place without making a copy of the array. +// Minimize the total number of operations. +// Credits: +// Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases. + +// Hide Company Tags Bloomberg Facebook +// Hide Tags Array Two Pointers +// Hide Similar Problems (E) Remove Element + + + +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +// var moveZeroes = function(nums) { +// var x = 0; +// var i = 0; +// while(i < nums.length) { +// if(nums[i] !== 0 && nums[x] === 0) { +// nums[x++] = nums[i]; +// nums[i++] = 0; +// } + +// while(nums[x] !== 0 && x < nums.length) { +// x++; +// } + +// if(i <= x) { +// i = x + 1; +// } + +// while(nums[i] === 0) { +// i++; +// } +// } +// }; + + + + +// // Simpler but slower algo +var moveZeroes = function(nums) { + y = 0; // y is none zero pointer + + // y only increase when i found a none zero number + // i only swap if i found a none zero number + for (var i = 0; i < nums.length; i++) { + if (nums[i] !== 0) { + var tmp = nums[i]; + nums[i] = nums[y]; + nums[y] = tmp; + y++; + } + } + + return nums; +}; +console.log(moveZeroes([0,1,0,3,12])); \ No newline at end of file diff --git a/285 Inorder Successor in BST.js b/285 Inorder Successor in BST.js new file mode 100644 index 0000000..e9f3430 --- /dev/null +++ b/285 Inorder Successor in BST.js @@ -0,0 +1,42 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @param {TreeNode} p + * @return {TreeNode} + */ +var inorderSuccessor = function(root, p) { + if(p.right) { // handle p = 14 or p = 27 + p = p.right; + while(p.left) { + p = p.left; + } + return p; + } + + // if p has no right child + + // 20 + // 10 25 + // 6 14 22 27 + // 1 9 + // 8 + + var succ = null; + while(root !== p) { + if(root.val > p.val) { // root is on the right hand side of p, handle case p = 1 + succ = root; + root = root.left; + } else if(root.val < p.val && root.right) { // handle case p = 8 + root = root.right; + } else { + break; + } + } + return succ; +}; \ No newline at end of file diff --git a/286 Walls and Gates.js b/286 Walls and Gates.js new file mode 100644 index 0000000..d6429eb --- /dev/null +++ b/286 Walls and Gates.js @@ -0,0 +1,90 @@ +// You are given a m x n 2D grid initialized with these three possible values. + +// -1 - A wall or an obstacle. +// 0 - A gate. +// INF - Infinity means an empty room. We use the value 231 - 1 = 2147483647 to represent INF as you may assume that the distance to a gate is less than 2147483647. +// Fill each empty room with the distance to its nearest gate. If it is impossible to reach a gate, it should be filled with INF. + +// For example, given the 2D grid: +// INF -1 0 INF +// INF INF INF -1 +// INF -1 INF -1 +// 0 -1 INF INF +// After running your function, the 2D grid should be: +// 3 -1 0 1 +// 2 2 1 -1 +// 1 -1 2 -1 +// 0 -1 3 4 +// Hide Company Tags Google Facebook +// Show Tags +// Show Similar Problems + +var wallsAndGates = function(rooms) { + var gates = []; + + if(!rooms || rooms.length === 0) { + return; + } + + var rows = rooms.length; + var cols = rooms[0].length; + + + for(var i = 0; i < rows; i++) { + for(var j = 0; j < cols; j++) { + // find all gates + if(rooms[i][j] === 0) { + traverse(rooms, i, j, rows, cols, 0); + } + } + } +}; + +function traverse(rooms, i, j, rows, cols, dist) { + if(i >= 0 && i < rows && j >= 0 && j < cols) { + if(rooms[i][j] !== -1 && rooms[i][j] >= dist) { + rooms[i][j] = dist; + traverse(rooms, i + 1, j, rows, cols, dist + 1); + traverse(rooms, i, j + 1, rows, cols, dist + 1); + traverse(rooms, i - 1, j, rows, cols, dist + 1); + traverse(rooms, i, j - 1, rows, cols, dist + 1); + } + } +} + + + + +// second attempt + +/** + * @param {number[][]} rooms + * @return {void} Do not return anything, modify rooms in-place instead. + */ +var wallsAndGates = function(rooms) { + for(var i = 0; i < rooms.length; i++) { + for(var j = 0; j < rooms[i].length; j++) { + if(rooms[i][j] === 0) { + dfs(rooms, i, j, 0); + } + } + } + + function dfs(rooms, i, j, dist) { + if(i >= 0 && i < rooms.length && j >= 0 && j < rooms[i].length) { + + if(rooms[i][j] === -1 || rooms[i][j] < dist) { + return; + } + + if(rooms[i][j] > dist) { + rooms[i][j] = dist; + } + + dfs(rooms, i + 1, j, dist + 1); + dfs(rooms, i - 1, j, dist + 1); + dfs(rooms, i, j + 1, dist + 1); + dfs(rooms, i, j - 1, dist + 1); + } + } +}; \ No newline at end of file diff --git a/289. Game of Life.js b/289. Game of Life.js new file mode 100644 index 0000000..e8b2fd9 --- /dev/null +++ b/289. Game of Life.js @@ -0,0 +1,54 @@ +/** + * @param {number[][]} board + * @return {void} Do not return anything, modify board in-place instead. + */ +var gameOfLife = function(board) { + // 3 over-population or under population + // 2 means reproduction + // 1 is alive + // 0 is dead + // if mod 2 === 1 means the current state is alive else dead + + + var rows = board.length; + var cols = board[0].length; + var dirX = [-1, 0, 1, 1, 1, 0,-1,-1]; + var dirY = [-1,-1,-1, 0, 1, 1, 1, 0]; + + for(var i = 0; i < rows; i++) { + for(var j = 0; j < cols; j++) { + var cur = board[i][j]; + var count = 0; + + for(var k = 0; k < 8; k++) { + var x = i + dirX[k]; + var y = j + dirY[k]; + if(x >= 0 && x <= rows && y >= 0 && y <= cols && board[x][y]%2 === 1) { + count++; + } + } + + if(board[i][j] === 1) { + if(count > 3 || count < 2) { + + + board[i][j] = 3; + } + } else { + if(count === 3) { + board[i][j] = 2; + } + } + } + } + + for(i = 0; i < rows; i++) { + for(j = 0; j < cols; j++) { + if(board[i][j] === 3) { + board[i][j] = 0; + } else if(board[i][j] === 2) { + board[i][j] = 1; + } + } + } +}; \ No newline at end of file diff --git a/293 Flip Game.js b/293 Flip Game.js new file mode 100644 index 0000000..3521531 --- /dev/null +++ b/293 Flip Game.js @@ -0,0 +1,38 @@ +// You are playing the following Flip Game with your friend: Given a string that contains only these two characters: + and -, you and your friend take turns to flip two consecutive "++" into "--". The game ends when a person can no longer make a move and therefore the other person will be the winner. + +// Write a function to compute all possible states of the string after one valid move. + +// For example, given s = "++++", after one move, it may become one of the following states: + +// [ +// "--++", +// "+--+", +// "++--" +// ] +// If there is no valid move, return an empty list []. + +// Hide Company Tags Google +// Hide Tags String +// Hide Similar Problems (M) Flip Game II + + +/** + * @param {string} s + * @return {string[]} + */ +var generatePossibleNextMoves = function(s) { + var result = []; + var arr = s.split(''); + + for(var i = 0; i < s.length - 1; i++) { + if(arr[i] === '+' && arr[i+1] === '+') { + arr[i] = '-'; + arr[i+1] = '-'; + result.push(arr.join('')); + arr[i] = '+'; + arr[i+1] = '+'; + } + } + + return result; +}; \ No newline at end of file diff --git a/294 Flip Game II.js b/294 Flip Game II.js new file mode 100644 index 0000000..7490041 --- /dev/null +++ b/294 Flip Game II.js @@ -0,0 +1,49 @@ +// You are playing the following Flip Game with your friend: Given a string that contains only these two characters: + and -, you and your friend take turns to flip two consecutive "++" into "--". The game ends when a person can no longer make a move and therefore the other person will be the winner. + +// Write a function to determine if the starting player can guarantee a win. + +// For example, given s = "++++", return true. The starting player can guarantee a win by flipping the middle "++" to become "+--+". + +// Follow up: +// Derive your algorithm's runtime complexity. + +// Hide Company Tags Google +// Hide Tags Backtracking +// Hide Similar Problems (E) Nim Game (E) Flip Game (M) Guess Number Higher or Lower II + + + +/** + * @param {string} s + * @return {boolean} + */ +var canWin = function(s) { + if(s === null || s.length === 0) { + return false; + } + + var arr = s.split(''); + + + // player 1 can guarantee win if the move player 1 made can lead to player 2 no win of winning + function checkCanWin(arr) { + for(var i = 0; i < arr.length - 1; i++) { + if(arr[i] === '+' && arr[i+1] === '+') { + arr[i] = arr[i+1] = '-'; + + var win = !checkCanWin(arr); + + arr[i] = arr[i+1] = '+'; + + if(win) { + return true; + } + } + } + + return false; + } + + + return checkCanWin(arr); +}; \ No newline at end of file diff --git a/295 Find Median From Data Stream.js b/295 Find Median From Data Stream.js new file mode 100644 index 0000000..e60177a --- /dev/null +++ b/295 Find Median From Data Stream.js @@ -0,0 +1,216 @@ +/** + * @constructor + */ +var MedianFinder = function() { + this.large = new MinHeap(); + this.small = new MaxHeap(); +}; + +/** + * @param {integer} word + * @return {void} + * Adds a num into the data structure. + */ +MedianFinder.prototype.addNum = function(num) { + var lg = this.large.peek(); // lg peek is the minimum of large set + var sm = this.small.peek(); // sm peek is the maximum of small set + + if(num <= sm) { + this.small.add(num); + } else { + this.large.add(num); + } + + var diff = this.small.size() - this.large.size(); + if(diff > 1) { + this.large.add(this.small.pop()); + } else if(diff < 0) { + this.small.add(this.large.pop()); + } +}; + + +/** + * @return {double} + * Return median of current data stream + */ +MedianFinder.prototype.findMedian = function() { + return this.small.size() > this.large.size() ? + this.small.peek() : (this.small.peek() + this.large.peek())/2; +}; + +/** + * Your MedianFinder object will be instantiated and called as such: + * var mf = new MedianFinder(); + * mf.addNum(1); + * mf.findMedian(); + */ + +class MaxHeap { + constructor() { + this.arr = []; + } + + peek() { + return this.arr[0] || null; + } + + size() { + return this.arr.length; + } + + pop() { + var arr = this.arr; + var len = arr.length; + + if(len === 0) { + return null; + } + + var max = arr[0]; + arr[0] = arr[len - 1] // swap the last value with max value + + arr.pop(); + + this.sinkDown(0); + + return max; + } + + add(val) { + var arr = this.arr; + arr.push(val); + this.bubbleUp(arr.length - 1); + } + + bubbleUp(n) { + var arr = this.arr; + + while(n > 0) { + var parentN = Math.floor((n + 1)/2) - 1; // [1,2,3] 1 as root 2 as left child and 3 as right child 2 has idx = 1 and 3 has idx = 2 1/2 will result in parent idx = 0 and 2/2 will result in parent idx = 1. So we need to add one to them and -1 at the end + + if(arr[parentN] > arr[n]) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[parentN]; + arr[parentN] = tmp; + n = parentN; + } + } + + sinkDown(n) { + var arr = this.arr; + var len = arr.length; + var val = arr[n]; + + while(true) { + + var swap = null; + var child2N = (n+1)*2; // root = 0 right child idx is (0 + 1)*2 = 2 + var child1N = child2N - 1; // right child idx - 1 = 1 for root's left child + + if(child1N < len && arr[child1N] > val) { + swap = child1N; + } + + if(child2N < len && arr[child2N] > val && arr[child2N] >= arr[child1N]) { + swap = child2N; + } + + if(swap === null) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[swap]; + arr[swap] = tmp; + n = swap; + } + } +} + + +class MinHeap { + constructor() { + this.arr = []; + } + + peek() { + return this.arr[0] || null; + } + + size() { + return this.arr.length; + } + + pop() { + var arr = this.arr; + var len = arr.length; + + if(len === 0) { + return null; + } + + var min = arr[0]; + arr[0] = arr[len - 1] // swap the last value with min value + + arr.pop(); + + this.sinkDown(0); + + return min; + } + + add(val) { + var arr = this.arr; + arr.push(val); + this.bubbleUp(arr.length - 1); + } + + bubbleUp(n) { + var arr = this.arr; + + while(n > 0) { + var parentN = Math.floor((n + 1)/2) - 1; // [1,2,3] 1 as root 2 as left child and 3 as right child 2 has idx = 1 and 3 has idx = 2 1/2 will result in parent idx = 0 and 2/2 will result in parent idx = 1. So we need to add one to them and -1 at the end + + if(arr[parentN] <= arr[n]) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[parentN]; + arr[parentN] = tmp; + n = parentN; + } + } + + sinkDown(n) { + var arr = this.arr; + var len = arr.length; + var val = arr[n] + + while(true) { + var swap = null; + var child2N = (n+1)*2; // root = 0 right child idx is (0 + 1)*2 = 2 + var child1N = child2N - 1; // right child idx - 1 = 1 for root's left child + if(child1N < len && arr[child1N] < val) { + swap = child1N; + } + + if(child2N < len && arr[child2N] < val && arr[child2N] <= arr[child1N]) { + swap = child2N; + } + + if(swap === null) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[swap]; + arr[swap] = tmp; + n = swap; + } + } +} \ No newline at end of file diff --git a/296 Best Meeting Point.js b/296 Best Meeting Point.js new file mode 100644 index 0000000..4af79c2 --- /dev/null +++ b/296 Best Meeting Point.js @@ -0,0 +1,56 @@ +// A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|. + +// For example, given three people living at (0,0), (0,4), and (2,2): + +// 1 - 0 - 0 - 0 - 1 +// | | | | | +// 0 - 0 - 0 - 0 - 0 +// | | | | | +// 0 - 0 - 1 - 0 - 0 +// The point (0,2) is an ideal meeting point, as the total travel distance of 2+2+2=6 is minimal. So return 6. + +// Show Hint +// Show Company Tags +// Show Tags +// Show Similar Problems + + +/** + * @param {number[][]} grid + * @return {number} + */ +var minTotalDistance = function(grid) { + var xpos = []; + var ypos = []; + + // get all positions + for(var x = 0; x < grid.length; x++) { + for(var y = 0; y < grid[0].length; y++) { + if(grid[x][y] === 1) { + xpos.push(x); + ypos.push(y); + } + } + } + + // no need to sort x + return getMedianPoint(xpos) + getMedianPoint(ypos, true); +}; + +var getMedianPoint = function(arr, shouldSort) { + if(shouldSort) { + arr.sort((a,b)=> { + return a > b ? 1 : -1; + }); + } + + var beg = 0; + var end = arr.length - 1; + var res = 0; + + while(beg < end) { + res += arr[end--] - arr[beg++]; + } + + return res; +} \ No newline at end of file diff --git a/297 Serialize and Deserialize Binary Tree My Submissions Question.js b/297 Serialize and Deserialize Binary Tree My Submissions Question.js index d9d3da0..ce6dad5 100644 --- a/297 Serialize and Deserialize Binary Tree My Submissions Question.js +++ b/297 Serialize and Deserialize Binary Tree My Submissions Question.js @@ -1,4 +1,26 @@ -/** +// Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment. + +// Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure. + +// For example, you may serialize the following tree + +// 1 +// / \ +// 2 3 +// / \ +// 4 5 +// as "[1,2,3,null,null,4,5]", just the same as how LeetCode OJ serializes a binary tree. You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself. +// Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless. + +// Credits: +// Special thanks to @Louis1992 for adding this problem and creating all test cases. + +// Hide Company Tags LinkedIn Google Uber Facebook Amazon Microsoft Yahoo Bloomberg +// Show Tags +// Show Similar Problems + + +/* * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; @@ -13,6 +35,9 @@ * @return {string} */ // http://fisherlei.blogspot.com/2013/03/interview-serialize-and-de-serialize.html + +// only pre order travesal can provide information about the root node +// the other technique that we can use is to use level order traversal var serialize = function(root) { var result = []; serializer(root, result); @@ -48,18 +73,15 @@ var deserialize = function(data) { var node = new TreeNode(parseInt(data[index])); index++; - node.left = deserializer(data, index); + node.left = deserializer(data); index++; - - node.right = deserializer(data, index); + node.right = deserializer(data); return node; } return deserializer(data); }; - - /** * Your functions will be called as such: * deserialize(serialize(root)); @@ -180,4 +202,4 @@ var deserialize = function(data) { /** * Your functions will be called as such: * deserialize(serialize(root)); - */ \ No newline at end of file + \ No newline at end of file diff --git a/300 Longest Increasing Subsequence.js b/300 Longest Increasing Subsequence.js new file mode 100644 index 0000000..c3cfc89 --- /dev/null +++ b/300 Longest Increasing Subsequence.js @@ -0,0 +1,43 @@ +// Given an unsorted array of integers, find the length of longest increasing subsequence. + +// For example, +// Given [10, 9, 2, 5, 3, 7, 101, 18], +// The longest increasing subsequence is [2, 3, 7, 101], therefore the length is 4. Note that there may be more than one LIS combination, it is only necessary for you to return the length. + +// Your algorithm should run in O(n2) complexity. + +// Follow up: Could you improve it to O(n log n) time complexity? + +// Credits: +// Special thanks to @pbrother for adding this problem and creating all test cases. + +// Hide Company Tags Microsoft +// Show Tags +// Show Similar Problems +/** + * @param {number[]} nums + * @return {number} + */ +var lengthOfLIS = function(nums) { + var size = nums.length; + + if(size === 0) { + return 0; + } + + dp = Array(size).fill(1); + + for(var i = 1; i < size; i++) { + for(var j = 0; j < i; j++) { + if(nums[i] > nums[j]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + + return Math.max.apply(null, dp); +}; + + + +console.log(Infinity < Infinity) \ No newline at end of file diff --git a/301 Remove Invalid Parentheses.js b/301 Remove Invalid Parentheses.js new file mode 100644 index 0000000..a2642e7 --- /dev/null +++ b/301 Remove Invalid Parentheses.js @@ -0,0 +1,79 @@ +// Remove the minimum number of invalid parentheses in order to make the input string valid. Return all possible results. + +// Note: The input string may contain letters other than the parentheses ( and ). + +// Examples: +// "()())()" -> ["()()()", "(())()"] +// "(a)())()" -> ["(a)()()", "(a())()"] +// ")(" -> [""] +// Credits: +// Special thanks to @hpplayer for adding this problem and creating all test cases. + +// Hide Company Tags Facebook +// Hide Tags Depth-first Search Breadth-first Search +// Hide Similar Problems (E) Valid Parentheses + + +/** + * @param {string} s + * @return {string[]} + */ + +function isValid(s) { + var count = 0; + + for(var i = 0; i < s.length; i++) { + if(s[i] === '(') { + count++; + } else if(s[i] === ')') { + count--; + } + + if(count < 0) { + return false; + } + } + + return count === 0; +} + +var removeInvalidParentheses = function(s) { + var queue = []; + queue.push(s); + var visited = {}; + var res = []; + var found = false; + + + // breadth first search since we are looking for the minimum changes + while(queue.length > 0) { + s = queue.shift(); + + // things stored in the queue represent the same level (same number of changes) + // once we found a valid one, we should not look further into the next level (by setting found to true) + if(isValid(s)) { + res.push(s); + found = true; + } + + if(found) { + continue; + } + + // if nothing found, then loop through the entire string and remove one of the parenthesis. + for(var i = 0; i < s.length; i++) { + if(s[i] !== '(' && s[i] !== ')') { + continue; + } + + var newS = s.substring(0,i) + s.substring(i + 1); + + if(!visited[newS]) { + visited[newS] = true; + queue.push(newS); + } + } + } + + return res; +}; \ No newline at end of file diff --git a/307 Range Sum Query - Mutable.js b/307 Range Sum Query - Mutable.js new file mode 100644 index 0000000..2bfda14 --- /dev/null +++ b/307 Range Sum Query - Mutable.js @@ -0,0 +1 @@ +// http://bookshadow.com/weblog/2015/08/13/segment-tree-set-1-sum-of-given-range/ \ No newline at end of file diff --git a/31 Next Permutation.js b/31 Next Permutation.js index 214b022..1f90369 100644 --- a/31 Next Permutation.js +++ b/31 Next Permutation.js @@ -6,13 +6,22 @@ var nextPermutation = function(nums) { var vioIndex = nums.length - 1; + + // example + // 1. 687432 + // the violation index is 1 (number 8) since it's greater than index 0 (number 6) + // 2. 87452 + // the violation index is 3 (number 5) since it's greater than index 2 (number 4) while(vioIndex > 0) { if(nums[vioIndex - 1] < nums[vioIndex]) { break; } vioIndex--; } - + + + // If it's not already the maximum value i.e. 876432 in the example of 687432 the maximum is 876432 + // then swap the the 6 with 7 since 7 a just a tad bigger if(vioIndex > 0) { vioIndex--; var first = nums.length - 1; @@ -37,4 +46,49 @@ var nextPermutation = function(nums) { end--; vioIndex++; } +}; + + + +/** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ +var nextPermutation = function(nums) { + var violatedIndex = nums.length - 1; + + while(violatedIndex > 0) { + if (nums[violatedIndex] > nums[violatedIndex-1]) { + break; + } + violatedIndex--; + } + + // max + if (violatedIndex > 0) { + violatedIndex--; + + var indexToSwapWith = nums.length - 1; + while(indexToSwapWith > violatedIndex) { + if (nums[indexToSwapWith] > nums[violatedIndex]) { + var temp = nums[violatedIndex]; + nums[violatedIndex] = nums[indexToSwapWith]; + nums[indexToSwapWith] = temp; + break; + } + indexToSwapWith-- + } + + violatedIndex++; + } + + var end = nums.length - 1; + + while(end > violatedIndex) { + temp = nums[violatedIndex]; + nums[violatedIndex] = nums[end]; + nums[end] = temp; + end-- + violatedIndex++; + } }; \ No newline at end of file diff --git a/311 Sparse Matrix Multiplication.js b/311 Sparse Matrix Multiplication.js new file mode 100644 index 0000000..aef291c --- /dev/null +++ b/311 Sparse Matrix Multiplication.js @@ -0,0 +1,97 @@ +// Given two sparse matrices A and B, return the result of AB. + +// You may assume that A's column number is equal to B's row number. + +// Example: + +// A = [ +// [ 1, 0, 0], +// [-1, 0, 3] +// ] + +// B = [ +// [ 7, 0, 0 ], +// [ 0, 0, 0 ], +// [ 0, 0, 1 ] +// ] + + +// | 1 0 0 | | 7 0 0 | | 7 0 0 | +// AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 | +// | 0 0 1 | +// Hide Company Tags LinkedIn Facebook +// Hide Tags Hash Table + + +/** + * @param {number[][]} A + * @param {number[][]} B + * @return {number[][]} + */ + +// normal matrix mulitplication +// slower version +var multiply = function(A, B) { + var result = []; + + var rowA = A.length; + var colA = A[0].length; + var rowB = B.length; + var colB = B[0].length + + for(var i = 0; i < rowA; i++) { + result.push(Array(colB).fill(0)); + + for(var j = 0; j < colB; j++) { + + for(var k = 0; k < colA; k++) { + result[i][j] += A[i][k]*B[k][j] + } + + } + } + + return result; +}; + +// faster +// skip +multiply = function(A, B) { + var result = []; + var i,j,k; + + var rowA = A.length; + var colA = A[0].length; + var colB = B[0].length + + for(var i = 0; i < rowA; i++) { + result.push(Array(colB).fill(0)); + } + + for(i = 0; i < rowA; i++) { + for(k = 0; k < colA; k++) { + if(A[i][k] !== 0) { + for(j = 0; j < colB; j++) { + if(B[k][j] !== 0) { + result[i][j] += A[i][k]*B[k][j]; + } + } + } + } + } + + return result; +}; + + + +// var data1 = [[0,1],[0,0],[0,1]]; +// var data2 = [[1,0],[1,0]]; + +// var data1 = [[1,0,0],[-1,0,3]]; +// var data2 = [[7,0,0],[0,0,0],[0,0,1]]; + +var data1 = [[1,-5]]; +var data2 = [[12],[-1]]; + +console.log(multiply(data1,data2)); \ No newline at end of file diff --git a/314 Binary Tree Vertical Order Traversal.js b/314 Binary Tree Vertical Order Traversal.js new file mode 100644 index 0000000..633552a --- /dev/null +++ b/314 Binary Tree Vertical Order Traversal.js @@ -0,0 +1,58 @@ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ + +var verticalOrder = function(root) { + var res = []; + + if(root === null) { + return res; + } + + var hash = {}; + var queue = []; + queue.push([root, 0]); + var min = Infinity; + var max = -Infinity; + + while(queue.length) { + var len = queue.length; + + for(var i = 0; i < len; i++) { + var pair = queue.shift(); + var node = pair[0]; + var order = pair[1]; + + hash[order] = hash[order] || []; + hash[order].push(node.val); + + min = Math.min(order, min); + max = Math.max(order, max); + + if(node.left) { + queue.push([node.left, order - 1]); + } + + if(node.right) { + queue.push([node.right, order + 1]); + } + } + } + + while(min <= max) { + if(hash[min].length) { + res.push(hash[min]); + } + min++; + } + + return res; +}; \ No newline at end of file diff --git a/317 Shortest Distance From All Buildings.js b/317 Shortest Distance From All Buildings.js new file mode 100644 index 0000000..45e899e --- /dev/null +++ b/317 Shortest Distance From All Buildings.js @@ -0,0 +1,97 @@ +/** + * @param {number[][]} grid + * @return {number} + */ +var shortestDistance = function(grid) { + var rows = grid.length; + if(rows === 0) { + return -1; + } + + var cols = grid[0].length; + // 2D array that records sum distances to all buildings + var dist = []; + + // 2D array that records how many buildings can visit here + var nums = []; + + for(var row = 0; row < rows; row++) { + dist.push([]); + nums.push([]); + + for(var col = 0; col < cols; col++) { + dist[row][col] = 0; + nums[row][col] = 0; + } + } + + var buildingNum = 0; + + for(row = 0; row < rows; row++) { + for(col = 0; col < cols; col++) { + if(grid[row][col] === 1) { + buildingNum++; + bfs(grid, row, col, dist, nums); + } + } + } + + var min = Infinity; + + for(row = 0; row < rows; row++) { + for(col = 0; col < cols; col++) { + if(grid[row][col] === 0 && dist[row][col] !== 0 && nums[row][col] === buildingNum) { + min = Math.min(min, dist[row][col]); + } + } + } + + if(min < Infinity) { + return min; + } + + return -1; +}; + +function bfs(grid, begCol, begRow, dist, nums) { + var rows = grid.length; + var cols = grid[0].length; + var queue = []; + queue.push([begRow, begCol]); + var dirs = [[-1,0],[0,1],[1,0],[0,-1]]; + var level = 0; + + // record if location is visited + var visited = []; + // init visited to all false + for(var row = 0; row < rows; row++) { + visited.push([]); + for(var col = 0; col < cols; col++) { + visited[row][col] = false; + } + } + + while(queue.length !== 0) { + level++; + var len = queue.length; + + for(var i = 0; i < len; i++) { + var coords = queue.shift(); + for(var j =0; j < dirs.length; j++) { + var x = coords[0] + dirs[j][0]; + var y = coords[1] + dirs[j][1]; + + if(x >= 0 && x < rows && y >= 0 && y < cols && !visited[x][y] && grid[x][y] === 0) { + visited[x][y] = true; + + dist[x][y] += level; + nums[x][y]++; + queue.push([x,y]); + } + } + } + } +} + + +function init2D \ No newline at end of file diff --git a/320 Generalized Abbreviation.js b/320 Generalized Abbreviation.js new file mode 100644 index 0000000..ed6ff12 --- /dev/null +++ b/320 Generalized Abbreviation.js @@ -0,0 +1,30 @@ +// Write a function to generate the generalized abbreviations of a word. + +// Example: +// Given word = "word", return the following list (order does not matter): +// ["word", "1ord", "w1rd", "wo1d", "wor1", "2rd", "w2d", "wo2", "1o1d", "1or1", "w1r1", "1o2", "2r1", "3d", "w3", "4"] +// Hide Company Tags Google +// Hide Tags + +/** + * @param {string} word + * @return {string[]} + */ +var generateAbbreviations = function(word) { + var result = []; + dfs(result, word, 0, '', 0); + return result; +}; + +var dfs = function(result, word, pos, cur, count) { + if(pos === word.length) { + if(count > 0) { + cur += count; + } + result.push(cur); + return; + } + + dfs(result, word, pos + 1, cur, count + 1); + dfs(result, word, pos + 1, cur + (count > 0 ? count : '') + word[pos], 0); +} diff --git a/322 Coin Change.js b/322 Coin Change.js index 6626e84..33da65e 100644 --- a/322 Coin Change.js +++ b/322 Coin Change.js @@ -9,6 +9,7 @@ var coinChange = function(coins, amount) { dp.push(-1); } + for(var a = 0; a < amount; a++) { if(dp[a] < 0) { continue; @@ -21,11 +22,15 @@ var coinChange = function(coins, amount) { continue; } - if(dp[a + coin] < 0 || dp[a + coin] > dp[a] + 1) { - dp[a+coin] = dp[a] + 1; + // if(dp[a + coin] < 0 || dp[a + coin] > dp[a] + 1) { + if(dp[a + coin] < 0) { + dp[a + coin] = dp[a] + 1; } } } - + console.log(dp) + console.log(dp[amount]) return dp[amount]; -}; \ No newline at end of file +}; + +coinChange([1,2,5,10,25], 25); \ No newline at end of file diff --git a/325 Maximum Size Subarray Sum Equals k.js b/325 Maximum Size Subarray Sum Equals k.js new file mode 100644 index 0000000..a49ec87 --- /dev/null +++ b/325 Maximum Size Subarray Sum Equals k.js @@ -0,0 +1,44 @@ +// Given an array nums and a target value k, find the maximum length of a subarray that sums to k. If there isn't one, return 0 instead. + +// Example 1: +// Given nums = [1, -1, 5, -2, 3], k = 3, +// return 4. (because the subarray [1, -1, 5, -2] sums to 3 and is the longest) + +// Example 2: +// Given nums = [-2, -1, 2, 1], k = 1, +// return 2. (because the subarray [-1, 2] sums to 1 and is the longest) + +// Follow Up: +// Can you do it in O(n) time? + +// Hide Company Tags Palantir Facebook +// Hide Tags Hash Table +// Hide Similar Problems (M) Minimum Size Subarray Sum (E) Range Sum Query - Immutable + + +/** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ +var maxSubArrayLen = function(nums, k) { + var maxLen = 0; + var currSum = 0; + var dict = { 0: -1 }; + + for(var i = 0; i < nums.length; i++) { + currSum += nums[i]; + + // since we are looking for the maxlen, dict is used to store the very first + // location where currSum occurred + if(dict[currSum] === undefined) { + dict[currSum] = i; + } + + if(dict[currSum - k] !== undefined) { + maxLen = Math.max(maxLen, i - dict[currSum - k]); + } + } + + return maxLen; +}; \ No newline at end of file diff --git a/33 Search in Rotated Sorted Array.js b/33 Search in Rotated Sorted Array.js new file mode 100644 index 0000000..97cb72f --- /dev/null +++ b/33 Search in Rotated Sorted Array.js @@ -0,0 +1,46 @@ +// Suppose a sorted array is rotated at some pivot unknown to you beforehand. + +// (i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2). + +// You are given a target value to search. If found in the array return its index, otherwise return -1. + +// You may assume no duplicate exists in the array. + + +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +var search = function(nums, target) { + var left = 0; + var right = nums.length - 1; + + while(left <= right) { + var mid = parseInt((left + right)/2); + if(nums[mid] === target) { + return mid; + } + + if(nums[mid] >= nums[left]) { // correct order + + if(nums[left] <= target && target < nums[mid]) { + // target is within the correct order part + right = mid - 1; + } else { + // target is not within the correct order part + left = mid + 1; + } + } else { // incorrect order + if(nums[mid] < target && target <= nums[right]) { + // target is within the correct order part + left = mid + 1; + } else { + // target is not within the correct order part + right = mid - 1; + } + } + } + + return -1; +}; \ No newline at end of file diff --git a/334 Increasing Triplet Subsequence.js b/334 Increasing Triplet Subsequence.js new file mode 100644 index 0000000..ca96da9 --- /dev/null +++ b/334 Increasing Triplet Subsequence.js @@ -0,0 +1,41 @@ +// Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the array. + +// Formally the function should: +// Return true if there exists i, j, k +// such that arr[i] < arr[j] < arr[k] given 0 ≤ i < j < k ≤ n-1 else return false. +// Your algorithm should run in O(n) time complexity and O(1) space complexity. + +// Examples: +// Given [1, 2, 3, 4, 5], +// return true. + +// Given [5, 4, 3, 2, 1], +// return false. + +// Credits: +// Special thanks to @DjangoUnchained for adding this problem and creating all test cases. + +// Hide Company Tags Facebook +// Hide Similar Problems (M) Longest Increasing Subsequence + + +/** + * @param {number[]} nums + * @return {boolean} + */ +var increasingTriplet = function(nums) { + var min1 = Infinity; + var min2 = Infinity; + + for(var i = 0; i < nums.length; i++) { + if(nums[i] <= min1) { + min1 = nums[i]; + } else if(nums[i] <= min2) { + min2 = nums[i]; + } else { + return true; + } + } + + return false; +}; \ No newline at end of file diff --git a/335 Self Crossing.js b/335 Self Crossing.js new file mode 100644 index 0000000..fa51554 --- /dev/null +++ b/335 Self Crossing.js @@ -0,0 +1,22 @@ +/** + * @param {number[]} x + * @return {boolean} + */ + +// http://www.cnblogs.com/grandyang/p/5216856.html +var isSelfCrossing = function(x) { + + for(var i = 3; i < x.length; i++) { + if (x[i] >= x[i - 2] && x[i - 3] >= x[i - 1]) { + return true; + } + if(i >= 4 && x[i-1] == x[i-3] && x[i] >= (x[i-2] - x[i-4])) { + return true; + } + if(i >= 5 && x[i-2] >= x[i-4] && x[i-3] >= x[i-1] && x[i-1] >= (x[i-3] - x[i-5]) && x[i] >= (x[i-2] - x[i-4])) { + return true; + } + } + + return false; +}; \ No newline at end of file diff --git a/337 House Robber III.js b/337 House Robber III.js new file mode 100644 index 0000000..c467c26 --- /dev/null +++ b/337 House Robber III.js @@ -0,0 +1,53 @@ +// The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night. + +// Determine the maximum amount of money the thief can rob tonight without alerting the police. + +// Example 1: +// 3 +// / \ +// 2 3 +// \ \ +// 3 1 +// Maximum amount of money the thief can rob = 3 + 3 + 1 = 7. +// Example 2: +// 3 +// / \ +// 4 5 +// / \ \ +// 1 3 1 +// Maximum amount of money the thief can rob = 4 + 5 = 9. + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number} + */ +var rob = function(root) { + var result = robViaDfs(root); + return Math.max.apply(null, result); +}; + + +// Array[0] max money when root is selected +// Array[1] max money when root is Not selected +function robViaDfs(root) { + if (!root) { + return [0, 0]; + } + + var left = robViaDfs(root.left), + right = robViaDfs(root.right), + includeRoot, + notIncludeRoot; + + includeRoot = left[1] + right[1] + root.val; // array[1] is value from before of not including root + notIncludeRoot = Math.max.apply(null, left) + Math.max.apply(null, right); + + return [includeRoot, notIncludeRoot]; +} diff --git a/338 Count Bits.js b/338 Count Bits.js new file mode 100644 index 0000000..ffea316 --- /dev/null +++ b/338 Count Bits.js @@ -0,0 +1,36 @@ +// Given a non negative integer number num. For every numbers i in the range 0 ≤ i ≤ num calculate the number of 1's in their binary representation and return them as an array. + +// Example: +// For num = 5 you should return [0,1,1,2,1,2]. + +// Follow up: + +// It is very easy to come up with a solution with run time O(n*sizeof(integer)). But can you do it in linear time O(n) /possibly in a single pass? +// Space complexity should be O(n). +// Can you do it like a boss? Do it without using any builtin function like __builtin_popcount in c++ or in any other language. +// Show Hint +// Credits: +// Special thanks to @ syedee for adding this problem and creating all test cases. + +// Hide Tags Dynamic Programming Bit Manipulation +// Hide Similar Problems (E) Number of 1 Bits + + + +var countBits = function(num) { + var ans = [0]; + + for(var i = 1; i <= num; i++) { + ans[i] = (ans[i] || 0) + ans[i&(i-1)] + 1; + } + + return ans; +}; + +// 0 0 0 1 +// 0 0 1 0 +// 0 0 1 1 +// 0 1 0 0 + + +console.log(countBits(3)); \ No newline at end of file diff --git a/339 Nested List Weight Sum.js b/339 Nested List Weight Sum.js new file mode 100644 index 0000000..d1c8ab3 --- /dev/null +++ b/339 Nested List Weight Sum.js @@ -0,0 +1,64 @@ +// Given a nested list of integers, return the sum of all integers in the list weighted by their depth. + +// Each element is either an integer, or a list -- whose elements may also be integers or other lists. + +// Example 1: +// Given the list [[1,1],2,[1,1]], return 10. (four 1's at depth 2, one 2 at depth 1) + +// Example 2: +// Given the list [1,[4,[6]]], return 27. (one 1 at depth 1, one 4 at depth 2, and one 6 at depth 3; 1 + 4*2 + 6*3 = 27) + +// Hide Company Tags LinkedIn +// Show Tags +// Show Similar Problems + + +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * function NestedInteger() { + * + * Return true if this NestedInteger holds a single integer, rather than a nested list. + * @return {boolean} + * this.isInteger = function() { + * ... + * }; + * + * Return the single integer that this NestedInteger holds, if it holds a single integer + * Return null if this NestedInteger holds a nested list + * @return {integer} + * this.getInteger = function() { + * ... + * }; + * + * Return the nested list that this NestedInteger holds, if it holds a nested list + * Return null if this NestedInteger holds a single integer + * @return {NestedInteger[]} + * this.getList = function() { + * ... + * }; + * }; + */ +/** + * @param {NestedInteger[]} nestedList + * @return {number} + */ + +var depthSum = function(nestedList) { + + function traverse(arr, lvl) { + var sum = 0; + + for(var i = 0; i < arr.length; i++) { + if(arr[i].isInteger()) { + sum += arr[i].getInteger()*lvl; + } else { + sum += traverse(arr[i].getList(), lvl + 1); + } + } + + return sum; + } + + return traverse(nestedList, 1); +}; \ No newline at end of file diff --git a/340 Longest Substring With At Most K Distinct Characters.js b/340 Longest Substring With At Most K Distinct Characters.js new file mode 100644 index 0000000..1223629 --- /dev/null +++ b/340 Longest Substring With At Most K Distinct Characters.js @@ -0,0 +1,49 @@ +/** + * @param {string} s + * @param {number} k + * @return {number} + */ +var lengthOfLongestSubstringKDistinct = function(s, k) { + var longestSubstr = ""; + var maxLength = 0; + var start = 0; + var map = new Map(); + + if(k === 0) { + return 0; + } + + for(var i = 0; i < s.length; i++) { + var c = s.charAt(i); + + // if map already contains two distrinct chars and the char is new to the map + if(map.size >= k && map.get(c) === undefined) { + var leftMost = s.length; + + // Calc substring len before the new char + if(i - start > maxLength) { + // Should not include i, since i is the new distinct char's index + longestSubstr = s.substring(start, i); + maxLength = longestSubstr.length; + } + + map.forEach((charIdx, key)=> { + if(charIdx < leftMost) { + leftMost = charIdx; + } + }); + + start = leftMost + 1; + map.delete(s[leftMost]); + } + + map.set(c, i); + } + + if(s.length - start > maxLength) { + longestSubstr = s.substring(start, s.length); + maxLength = longestSubstr.length; + } + + return maxLength; +}; \ No newline at end of file diff --git a/341 Flatten Nested List Iterator.js b/341 Flatten Nested List Iterator.js new file mode 100644 index 0000000..c82b569 --- /dev/null +++ b/341 Flatten Nested List Iterator.js @@ -0,0 +1,95 @@ +// Given a nested list of integers, implement an iterator to flatten it. + +// Each element is either an integer, or a list -- whose elements may also be integers or other lists. + +// Example 1: +// Given the list [[1,1],2,[1,1]], + +// By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,1,2,1,1]. + +// Example 2: +// Given the list [1,[4,[6]]], + +// By calling next repeatedly until hasNext returns false, the order of elements returned by next should be: [1,4,6]. + +// Hide Company Tags Google Facebook Twitter +// Hide Tags Stack Design +// Hide Similar Problems (M) Flatten 2D Vector (M) Zigzag Iterator + + + +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * function NestedInteger() { + * + * Return true if this NestedInteger holds a single integer, rather than a nested list. + * @return {boolean} + * this.isInteger = function() { + * ... + * }; + * + * Return the single integer that this NestedInteger holds, if it holds a single integer + * Return null if this NestedInteger holds a nested list + * @return {integer} + * this.getInteger = function() { + * ... + * }; + * + * Return the nested list that this NestedInteger holds, if it holds a nested list + * Return null if this NestedInteger holds a single integer + * @return {NestedInteger[]} + * this.getList = function() { + * ... + * }; + * }; + */ +/** + * @constructor + * @param {NestedInteger[]} nestedList + */ +var NestedIterator = function(nestedList) { + this.stack = []; + + for(var i = nestedList.length; i--;) { + this.stack.push(nestedList[i]); + } +}; + + +/** + * @this NestedIterator + * @returns {boolean} + */ +NestedIterator.prototype.hasNext = function() { + // keep looping until we found insert an integer in the stack + while(this.stack.length > 0) { + var next = this.stack[this.stack.length - 1]; + + if(next.isInteger()) { + return true; + } + + this.stack.pop(); + var list = next.getList(); + for(var i = list.length; i--;) { + this.stack.push(list[i]); + } + } + + return false; +}; + +/** + * @this NestedIterator + * @returns {integer} + */ +NestedIterator.prototype.next = function() { + return this.stack.pop(); +}; + +/** + * Your NestedIterator will be called like this: + * var i = new NestedIterator(nestedList), a = []; + * while (i.hasNext()) a.push(i.next()); +*/ \ No newline at end of file diff --git a/348. Design Tic-Tac-Toe.java b/348. Design Tic-Tac-Toe.java new file mode 100644 index 0000000..f00d77b --- /dev/null +++ b/348. Design Tic-Tac-Toe.java @@ -0,0 +1,103 @@ +// Design a Tic-tac-toe game that is played between two players on a n x n grid. + +// You may assume the following rules: + +// A move is guaranteed to be valid and is placed on an empty block. +// Once a winning condition is reached, no more moves is allowed. +// A player who succeeds in placing n of their marks in a horizontal, vertical, or diagonal row wins the game. +// Example: +// Given n = 3, assume that player 1 is "X" and player 2 is "O" in the board. + +// TicTacToe toe = new TicTacToe(3); + +// toe.move(0, 0, 1); -> Returns 0 (no one wins) +// |X| | | +// | | | | // Player 1 makes a move at (0, 0). +// | | | | + +// toe.move(0, 2, 2); -> Returns 0 (no one wins) +// |X| |O| +// | | | | // Player 2 makes a move at (0, 2). +// | | | | + +// toe.move(2, 2, 1); -> Returns 0 (no one wins) +// |X| |O| +// | | | | // Player 1 makes a move at (2, 2). +// | | |X| + +// toe.move(1, 1, 2); -> Returns 0 (no one wins) +// |X| |O| +// | |O| | // Player 2 makes a move at (1, 1). +// | | |X| + +// toe.move(2, 0, 1); -> Returns 0 (no one wins) +// |X| |O| +// | |O| | // Player 1 makes a move at (2, 0). +// |X| |X| + +// toe.move(1, 0, 2); -> Returns 0 (no one wins) +// |X| |O| +// |O|O| | // Player 2 makes a move at (1, 0). +// |X| |X| + +// toe.move(2, 1, 1); -> Returns 1 (player 1 wins) +// |X| |O| +// |O|O| | // Player 1 makes a move at (2, 1). +// |X|X|X| +// Follow up: +// Could you do better than O(n2) per move() operation? + + + +public class TicTacToe { + private int[] rows; + private int[] cols; + private int diagonal; + private int antiDiagonal; + private int size; + + /** Initialize your data structure here. */ + public TicTacToe(int n) { + rows = new int[n]; + cols = new int[n]; + size = n; + } + + /** Player {player} makes a move at ({row}, {col}). + @param row The row of the board. + @param col The column of the board. + @param player The player, can be either 1 or 2. + @return The current winning condition, can be either: + 0: No one wins. + 1: Player 1 wins. + 2: Player 2 wins. */ + public int move(int row, int col, int player) { + int toAdd = player == 1 ? 1 : -1; + + rows[row] += toAdd; + cols[col] += toAdd; + + if(row == col) { + diagonal += toAdd; + } + + if(col == cols.length - row - 1) { + antiDiagonal += toAdd; + } + + if(Math.abs(cols[col]) == size || + Math.abs(rows[row]) == size || + Math.abs(diagonal) == size || + Math.abs(antiDiagonal) == size) { + return player; + } + + return 0; + } +} + +/** + * Your TicTacToe object will be instantiated and called as such: + * TicTacToe obj = new TicTacToe(n); + * int param_1 = obj.move(row,col,player); + */ \ No newline at end of file diff --git a/349 Intersection of Two Arrays.js b/349 Intersection of Two Arrays.js new file mode 100644 index 0000000..850b43e --- /dev/null +++ b/349 Intersection of Two Arrays.js @@ -0,0 +1,43 @@ +// Given two arrays, write a function to compute their intersection. + +// Example: +// Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2]. + +// Note: +// Each element in the result must be unique. +// The result can be in any order. +// Hide Tags Binary Search Hash Table Two Pointers Sort +// Hide Similar Problems (E) Intersection of Two Arrays II + + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number[]} + */ +var intersection = function(nums1, nums2) { + var hash = {}; + var result = []; + var i = 0; + while(i < nums1.length || i < nums2.length) { + if(i < nums1.length) { + hash[nums1[i]] = hash[nums1[i]] || []; + hash[nums1[i]][0] = true; + } + + if(i < nums2.length) { + hash[nums2[i]] = hash[nums2[i]] || []; + hash[nums2[i]][1] = true; + } + + i++ + } + + for(i in hash) { + if(hash[i][0] && hash[i][1]) { + result.push(parseInt(i)); + } + } + + return result; +}; \ No newline at end of file diff --git a/35 Search Insert Position.js b/35 Search Insert Position.js index 40cc05c..bba8074 100644 --- a/35 Search Insert Position.js +++ b/35 Search Insert Position.js @@ -2,6 +2,37 @@ // Language: Javascript // Problem: https://leetcode.com/problems/search-insert-position/ // Author: Chihung Yu +/** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ +// var searchInsert = function(nums, target) { +// var left = 0; +// var right = nums.length - 1; +// +// while(left <= right){ +// var mid = parseInt((left + right)/2); +// +// var val = nums[mid]; +// +// if(val === target){ +// return mid; +// } else if(val > target){ +// right = mid - 1; +// } else { +// left = mid + 1; +// } +// } +// +// if(nums[left] < target){ +// return left + 1; +// } else { +// return left; +// } +// }; + + /** * @param {number[]} nums * @param {number} target @@ -10,24 +41,22 @@ var searchInsert = function(nums, target) { var left = 0; var right = nums.length - 1; - - while(left <= right){ - var mid = parseInt((left + right)/2); - - var val = nums[mid]; - - if(val === target){ + + while (left < right) { + var mid = left + Math.ceil((right - left)/2); + + if (nums[mid] === target) { return mid; - } else if(val > target){ + } else if (nums[mid] > target) { right = mid - 1; } else { left = mid + 1; } } - - if(nums[left] < target){ + + if (nums[left] < target) { return left + 1; } else { return left; } -}; \ No newline at end of file +} diff --git a/350 Intersection of Two Arrays II.js b/350 Intersection of Two Arrays II.js new file mode 100644 index 0000000..4d3a1af --- /dev/null +++ b/350 Intersection of Two Arrays II.js @@ -0,0 +1,52 @@ +// Given two arrays, write a function to compute their intersection. + +// Example: +// Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2]. + +// Note: +// Each element in the result should appear as many times as it shows in both arrays. +// The result can be in any order. +// Follow up: +// What if the given array is already sorted? How would you optimize your algorithm? +// What if nums1's size is small compared to nums2's size? Which algorithm is better? +// 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? +// Hide Tags Binary Search Hash Table Two Pointers Sort +// Hide Similar Problems (E) Intersection of Two Arrays + + + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number[]} + */ +var intersect = function(nums1, nums2) { + var hash = {}; + var arr1, arr2; + + if(nums1.length > nums2.length) { + arr1 = nums2; + arr2 = nums1; + } else { + arr1 = nums1; + arr2 = nums2; + } + + var count = arr1.length; + var result = []; + + for(var i = 0; i < arr1.length; i++) { + hash[arr1[i]] = hash[arr1[i]] || 0; + hash[arr1[i]]++; + } + + for(i = 0; i < arr2.length && count !== 0; i++) { + if(hash[arr2[i]] > 0) { + hash[arr2[i]]--; + count--; + result.push(arr2[i]); + } + } + + return result; +}; \ No newline at end of file diff --git a/353 Design Snake Game.js b/353 Design Snake Game.js new file mode 100644 index 0000000..cb16940 --- /dev/null +++ b/353 Design Snake Game.js @@ -0,0 +1,157 @@ +// Design a Snake game that is played on a device with screen size = width x height. Play the game online if you are not familiar with the game. + +// The snake is initially positioned at the top left corner (0,0) with length = 1 unit. + +// You are given a list of food's positions in row-column order. When a snake eats the food, its length and the game's score both increase by 1. + +// Each food appears one by one on the screen. For example, the second food will not appear until the first food was eaten by the snake. + +// When a food does appear on the screen, it is guaranteed that it will not appear on a block occupied by the snake. + +// Example: +// Given width = 3, height = 2, and food = [[1,2],[0,1]]. + +// Snake snake = new Snake(width, height, food); + +// Initially the snake appears at position (0,0) and the food at (1,2). + +// |S| | | +// | | |F| + +// snake.move("R"); -> Returns 0 + +// | |S| | +// | | |F| + +// snake.move("D"); -> Returns 0 + +// | | | | +// | |S|F| + +// snake.move("R"); -> Returns 1 (Snake eats the first food and right after that, the second food appears at (0,1) ) + +// | |F| | +// | |S|S| + +// snake.move("U"); -> Returns 1 + +// | |F|S| +// | | |S| + +// snake.move("L"); -> Returns 2 (Snake eats the second food) + +// | |S|S| +// | | |S| + +// snake.move("U"); -> Returns -1 (Game over because snake collides with border) + +// Credits: +// Special thanks to @elmirap for adding this problem and creating all test cases. + +// Hide Company Tags Google +// Hide Tags Design Queue + + + +public class SnakeGame { + + /** Initialize your data structure here. + @param width - screen width + @param height - screen height + @param food - A list of food positions + E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. */ + + private Set board = new HashSet<>(); + private int[][] food; + private int eat = 0; + private LinkedList snake = new LinkedList<>(); + private int width, height; + + + private boolean eat(int y, int x) { + if(eat >= food.length) { + return false; + } + if(food[eat][0] < 0 || food[eat][0] >= height || food[eat][1] <0 || food[eat][1] >= width) { + return false; + } + if(y == food[eat][0] && x == food[eat][1]) { + return true; + } + + return false; + } + + + public SnakeGame(int width, int height, int[][] food) { + this.food = food; + Position head = new Position(0,0); + this.snake.add(head); + board.add(head.toString()); + this.height = height; + this.width = width; + } + + /** Moves the snake. + @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down + @return The game's score after the move. Return -1 if game over. + Game over when snake crosses the screen boundary or bites its body. */ + public int move(String direction) { + Position head = snake.getFirst(); + Position next = new Position(head.y, head.x); + + if("U".equals(direction)) { + next.y--; + } else if("D".equals(direction)) { + next.y++; + } else if("L".equals(direction)) { + next.x--; + } else if("R".equals(direction)) { + next.x++; + } else { + return -1; + } + + if(next.y < 0 || next.y >= height || next.x < 0 || next.x >= width) { + return -1; + } + + String ns = next.toString(); + if(eat(next.y, next.x)) { + snake.addFirst(next); + board.add(ns); + return ++eat; + } + + Position tail = snake.getLast(); + board.remove(tail.toString()); + snake.removeLast(); + + if(board.contains(ns)) { + return -1; + } + + snake.addFirst(next); + board.add(ns); + return eat; + } +} + +class Position { + int x, y; + + Position(int y, int x) { + this.y = y; + this.x = x; + } + + public String toString() { + return y + "," + x; + } +} + +/** + * Your SnakeGame object will be instantiated and called as such: + * SnakeGame obj = new SnakeGame(width, height, food); + * int param_1 = obj.move(direction); + */ \ No newline at end of file diff --git a/364 Nested List Weight Sum II.js b/364 Nested List Weight Sum II.js new file mode 100644 index 0000000..be128f6 --- /dev/null +++ b/364 Nested List Weight Sum II.js @@ -0,0 +1,82 @@ +// Given a nested list of integers, return the sum of all integers in the list weighted by their depth. + +// Each element is either an integer, or a list -- whose elements may also be integers or other lists. + +// Different from the previous question where weight is increasing from root to leaf, now the weight is defined from bottom up. i.e., the leaf level integers have weight 1, and the root level integers have the largest weight. + +// Example 1: +// Given the list [[1,1],2,[1,1]], return 8. (four 1's at depth 1, one 2 at depth 2) + +// Example 2: +// Given the list [1,[4,[6]]], return 17. (one 1 at depth 3, one 4 at depth 2, and one 6 at depth 1; 1*3 + 4*2 + 6*1 = 17) + +// Hide Company Tags LinkedIn +// Show Tags +// Show Similar Problems + +/** + * // This is the interface that allows for creating nested lists. + * // You should not implement it, or speculate about its implementation + * function NestedInteger() { + * + * Return true if this NestedInteger holds a single integer, rather than a nested list. + * @return {boolean} + * this.isInteger = function() { + * ... + * }; + * + * Return the single integer that this NestedInteger holds, if it holds a single integer + * Return null if this NestedInteger holds a nested list + * @return {integer} + * this.getInteger = function() { + * ... + * }; + * + * Return the nested list that this NestedInteger holds, if it holds a nested list + * Return null if this NestedInteger holds a single integer + * @return {NestedInteger[]} + * this.getList = function() { + * ... + * }; + * }; + */ +/** + * @param {NestedInteger[]} nestedList + * @return {number} + */ +var depthSumInverse = function(nestedList) { + + function getDepth(arr, lvl) { + var maxDepth = lvl; + + for(var i = 0; i < arr.length; i++) { + if(!arr[i].isInteger()) { + // maxDepth represents the max depth at that level, + // e.g. [[[[55]]],[[31]],[99],[],75] + // at lvl 1, we want to know which [[[55]]], [[31]], [99], [], 75 + // has the maxDepth + maxDepth = Math.max(maxDepth, getDepth(arr[i].getList(), lvl + 1)); + } + } + + return maxDepth; + } + + var depth = getDepth(nestedList, 1); + + function traverse(arr, lvl) { + var sum = 0; + + for(var i = 0; i < arr.length; i++) { + if(arr[i].isInteger()) { + sum += arr[i].getInteger()*lvl; + } else { + sum += traverse(arr[i].getList(), lvl - 1); + } + } + + return sum; + } + + return traverse(nestedList, depth); +}; \ No newline at end of file diff --git a/366 Find Leaves of Binary Tree.js b/366 Find Leaves of Binary Tree.js new file mode 100644 index 0000000..21f1ed8 --- /dev/null +++ b/366 Find Leaves of Binary Tree.js @@ -0,0 +1,71 @@ +// Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves, repeat until the tree is empty. + +// Example: +// Given binary tree +// 1 +// / \ +// 2 3 +// / \ +// 4 5 +// Returns [4, 5, 3], [2], [1]. + +// Explanation: +// 1. Removing the leaves [4, 5, 3] would result in this tree: + +// 1 +// / +// 2 +// 2. Now removing the leaf [2] would result in this tree: + +// 1 +// 3. Now removing the leaf [1] would result in the empty tree: + +// [] +// Returns [4, 5, 3], [2], [1]. + +// Credits: +// Special thanks to @elmirap for adding this problem and creating all test cases. + +// Hide Company Tags LinkedIn +// Hide Tags Tree Depth-first Search + + + +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {TreeNode} root + * @return {number[][]} + */ +var findLeaves = function(root) { + var result = []; + + while(root) { + var leaves = [] + root = removeLeaves(root, leaves); + result.push(leaves); + } + + return result; +}; + +function removeLeaves(node, leaves) { + if(!node) { + return null; + } + + if(!node.left && !node.right) { + leaves.push(node.val); + return null; + } + + node.left = removeLeaves(node.left, leaves); + node.right = removeLeaves(node.right, leaves); + + return node; +} \ No newline at end of file diff --git a/367 Valid Perfect Square.js b/367 Valid Perfect Square.js new file mode 100644 index 0000000..3692c70 --- /dev/null +++ b/367 Valid Perfect Square.js @@ -0,0 +1,41 @@ +// Given a positive integer num, write a function which returns True if num is a perfect square else False. + +// Note: Do not use any built-in library function such as sqrt. + +// Example 1: + +// Input: 16 +// Returns: True +// Example 2: + +// Input: 14 +// Returns: False +// Credits: +// Special thanks to @elmirap for adding this problem and creating all test cases. + +// Hide Company Tags LinkedIn +// Show Tags +// Show Similar Problems + + +/** + * @param {number} num + * @return {boolean} + */ +var isPerfectSquare = function(num) { + var left = 0; + var right = num; + + while(left <= right) { + var mid = left + parseInt((right - left)/2); + var pow = mid*mid; + if(pow === num) { + return true; + } else if(pow < num) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return false; +}; \ No newline at end of file diff --git a/37 Sudoku Solver.js b/37 Sudoku Solver.js new file mode 100644 index 0000000..e69de29 diff --git a/371 Sum of Two Integers.js b/371 Sum of Two Integers.js new file mode 100644 index 0000000..2fe03aa --- /dev/null +++ b/371 Sum of Two Integers.js @@ -0,0 +1,26 @@ +// Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -. + +// Example: +// Given a = 1 and b = 2, return 3. + +/** + * @param {number} a + * @param {number} b + * @return {number} + */ +var getSum = function(a, b) { + while(b !== 0) { + + // 100 + // 101 + + // carry = a&b and carry << 1 will give 1 in the front + // a^b will give 001 which is addition. + // b now will become 1000 and we just need to do this one more time then we get the answer. + var carry = a & b; + a ^= b; + b = carry << 1; + } + + return a; +}; \ No newline at end of file diff --git a/38 Count and Say.js b/38 Count and Say.js index 13ea348..7bc589d 100644 --- a/38 Count and Say.js +++ b/38 Count and Say.js @@ -26,4 +26,29 @@ var countAndSay = function(n) { n--; } return cur; -}; \ No newline at end of file +}; + + +// var countAndSay = function(n) { +// var str = '1'; + +// for(var i = 1; i < n; i++) { +// var newStr = ''; +// var count = 1; + +// for(var j = 1; j < str.length; j++) { +// if(str[j] === str[j - 1]) { +// count++; +// } else { +// newStr += count + str[j - 1]; +// count = 1; +// } +// } + +// newStr += count + str[j - 1]; +// str = newStr; +// } + +// return str; +// }; + diff --git a/39 Combination Sum.js b/39 Combination Sum.js index c7e0fa2..d1878c5 100644 --- a/39 Combination Sum.js +++ b/39 Combination Sum.js @@ -1,3 +1,22 @@ +// Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. + +// The same repeated number may be chosen from C unlimited number of times. + +// Note: +// All numbers (including target) will be positive integers. +// The solution set must not contain duplicate combinations. +// For example, given candidate set [2, 3, 6, 7] and target 7, +// A solution set is: +// [ +// [7], +// [2, 2, 3] +// ] +// Hide Company Tags Snapchat Uber +// Hide Tags Array Backtracking +// Hide Similar Problems (M) Letter Combinations of a Phone Number (M) Combination Sum II (M) Combinations (M) Combination Sum III (M) Factor Combinations (M) Combination Sum IV + + + /** * @param {number[]} candidates * @param {number} target @@ -5,37 +24,58 @@ */ var combinationSum = function(candidates, target) { var result = []; - + if(candidates === null || candidates.length === 0){ return result; } - + candidates.sort(function(a,b){return a > b ? 1 : -1}); - + var output = []; - + generate(candidates, result, output, target, 0); - + return result; }; var generate = function(candidates, result, output, sum, index){ if(sum === 0){ - result.push(output.slice()); + result.push(output.slice()); } if(sum < 0){ return; } - + for(var i = index; i < candidates.length; i++){ if(i > index && candidates[i] === candidates[i - 1]){ continue; } - + if(candidates[i] <= sum){ output.push(candidates[i]); generate(candidates, result, output, sum - candidates[i], i); output.pop(); } } -} \ No newline at end of file +} + + +// Another solution +var combinationSum = function(candidates, target) { + var results = []; + comb(candidates.sort(), 0, [], 0, target, results); + return results; +}; + +var comb = function(cand, index, partial, partialSum, target, results) { + if(target === partialSum) { + results.push(partial); + return; + } + if(cand.length === index || partialSum > target) { + return; + } + comb(cand, index, partial.concat([cand[index]]), + partialSum + cand[index], target, results); + comb(cand, index + 1, partial, partialSum, target, results); +}; diff --git a/40 combination Sum II.js b/40 combination Sum II.js index 2e79154..00a4439 100644 --- a/40 combination Sum II.js +++ b/40 combination Sum II.js @@ -1,3 +1,23 @@ +// Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. + +// Each number in C may only be used once in the combination. + +// Note: +// All numbers (including target) will be positive integers. +// The solution set must not contain duplicate combinations. +// For example, given candidate set [10, 1, 2, 7, 6, 1, 5] and target 8, +// A solution set is: +// [ +// [1, 7], +// [1, 2, 5], +// [2, 6], +// [1, 1, 6] +// ] +// Hide Tags Array Backtracking +// Hide Similar Problems (M) Combination Sum + + + /** * @param {number[]} candidates * @param {number} target @@ -12,8 +32,6 @@ var combinationSum2 = function(candidates, target) { var output = []; candidates.sort(function(a,b){return a > b ? 1 : -1;}); - - console.log('c',candidates); generate(candidates, target, 0, result, output); return result; @@ -25,19 +43,17 @@ var generate = function(c, t, index, result, output){ } if(t === 0){ result.push(output.slice()); - console.log(output) return } - for(var i = index; i index && c[i] === c[i-1]) { + continue; + } var val = c[i]; - + output.push(val); - generate(c, t - val, i+1, result, output); + generate(c, t - val, i + 1, result, output); output.pop(); - - while(i < (c.length - 1) && c[i] === c[i+1]){ - i++; - } } } \ No newline at end of file diff --git a/42 Trapping Rain Water.js b/42 Trapping Rain Water.js new file mode 100644 index 0000000..f1922b2 --- /dev/null +++ b/42 Trapping Rain Water.js @@ -0,0 +1,50 @@ +// Given n non-negative integers representing an elevation map where the width of each bar is 1, compute how much water it is able to trap after raining. + +// For example, +// Given [0,1,0,2,1,0,1,3,2,1,2,1], return 6. + + +// The above elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water (blue section) are being trapped. Thanks Marcos for contributing this image! + + +// http://bangbingsyb.blogspot.com/2014/11/leetcode-trapping-rain-water.html + +/** + * @param {number[]} height + * @return {number} + */ +var trap = function(height) { + // scan left max + // scan right max + // e.g. heights: 0 3 2 1 5 1 + // left max: 0 0 3 3 3 5 + // right max: 5 5 5 5 1 0 + // what that means is? + // for index 1 -> height 3 + // 0 is its left max, 5 is its right max -> that gives zero volumn as it cannot hold water + // for index 2 -> height 2 + // 3 is its left max and 5 is its right max -> min(3,5) = 3 and height 2 is the bottom of the water bed, so that gives (3-2) -> 1 volumn of water + + var leftMax = []; + var rightMax= []; + var water = 0; + + // to get the left of i so we do i - 1 + for(var i = 1; i < height.length; i++) { + leftMax[i] = leftMax[i] || 0; + leftMax[i] = Math.max(leftMax[i - 1] || 0, height[i - 1]); + } + + for(i = height.length - 2; i >= 0; i--) { + rightMax[i] = rightMax[i] || 0; + rightMax[i] = Math.max(rightMax[i + 1] || 0, height[i + 1]); + + var minHeight = Math.min(leftMax[i], rightMax[i]); + var waterBottom = height[i]; + if(minHeight > waterBottom) { + water += (minHeight - waterBottom); + } + } + + return water; +}; \ No newline at end of file diff --git a/43 Multiply Strings.js b/43 Multiply Strings.js index eddba66..259a76e 100644 --- a/43 Multiply Strings.js +++ b/43 Multiply Strings.js @@ -1,44 +1,50 @@ +// Given two numbers represented as strings, return multiplication of the numbers as a string. + +// Note: +// The numbers can be arbitrarily large and are non-negative. +// Converting the input string to integer is NOT allowed. +// You should NOT use internal library such as BigInteger. +// Hide Company Tags Facebook Twitter +// Hide Tags Math String +// Hide Similar Problems (M) Add Two Numbers (E) Plus One (E) Add Binary + /** * @param {string} num1 * @param {string} num2 * @return {string} */ var multiply = function(num1, num2) { - if(num1 === null || num2 === null || num1.length === 0 || num2.length === 0){ - return 0; + if(num1 === null || num2 === null || num1.length === 0 || num2.length === 0 || num1 === '0' || num2 === '0') { + return '0'; } var arr1 = num1.split('').reverse(); var arr2 = num2.split('').reverse(); - var result = []; - for(var i = 0; i < arr1.length; i++){ + for(var i = 0; i < arr1.length; i++) { var carry = 0; + var val1 = parseInt(arr1[i]); - for(var j = 0; j < arr2.length; j++){ - var n1 = parseInt(arr1[i]); - var n2 = parseInt(arr2[j]); - var exist = parseInt(result[i+j] || 0); - var total = n1*n2+carry+exist; - - var remain = total%10 + ''; - carry = parseInt(total/10); - result[i+j] = remain; + for(var j = 0; j < arr2.length; j++) { + var val2 = parseInt(arr2[j]); + var product = val1*val2 + carry; + var exist = result[i+j] || 0; + var sum = product + exist; + var digit = sum%10; + carry = Math.floor(sum/10); + result[i+j] = digit; } - if(carry > 0){ - result[i + j] = carry + ''; + if(carry > 0) { + result[i+j] = carry; } } - result = result.reverse(); + result.reverse(); result = result.join(''); - result = result.replace(/^0+/g,''); - if(result.length === 0){ - return "0"; - } else { - return result; - } -}; \ No newline at end of file + return result; +}; + +multiply('123', '456') \ No newline at end of file diff --git a/44 Wildcard Matching.js b/44 Wildcard Matching.js new file mode 100644 index 0000000..9abccbc --- /dev/null +++ b/44 Wildcard Matching.js @@ -0,0 +1,87 @@ +// Implement wildcard pattern matching with support for '?' and '*'. + +// '?' Matches any single character. +// '*' Matches any sequence of characters (including the empty sequence). + +// The matching should cover the entire input string (not partial). + +// The function prototype should be: +// bool isMatch(const char *s, const char *p) + +// Some examples: +// isMatch("aa","a") → false +// isMatch("aa","aa") → true +// isMatch("aaa","aa") → false +// isMatch("aa", "*") → true +// isMatch("aa", "a*") → true +// isMatch("ab", "?*") → true +// isMatch("aab", "c*a*b") → false +// Hide Company Tags Google Snapchat Facebook +// Hide Tags Dynamic Programming Backtracking Greedy String +// Hide Similar Problems (H) Regular Expression Matching + + + +/** + * @param {string} s + * @param {string} p + * @return {boolean} + */ + +var matchChar = function(c, p){ + return (p === '?' || p === c); +} +var isMatch = function(s, p) { + if(s === null || p === null) { + return false; + } + + var idxS = 0; + var idxP = 0; + + var lenS = s.length; + var lenP = p.length; + + var back = false; + var preS = 0; + var preP = 0; + + while(idxS < lenS) { + var charS = s[idxS]; + var charP = p[idxP]; + + if(idxP < lenP && matchChar(s[idxS], p[idxP])) { + idxP++; + idxS++; + } else if(idxP < lenP && p[idxP] === '*') { + while(idxP < lenP && p[idxP] === '*') { + idxP++; + } + + back = true; + preS = idxS; + preP = idxP; + } else if(back) { + // since * means any sequence including ''. We can use greedy approach + // str = "abefcdgiescdfimde" pattern = "ab*cd?i*de" + // first * is "ef" first ? is "g" second * is escdfim + idxS = ++preS; + idxP = preP; + // preP is the pattern index after * + // even idxP got advanced by first the condition idxP < lenP && matchChar(s[idxS], p[idxP]) + // when the first and second condition don't work out, we backtrack of using the last wild card position. + } else { + return false; + } + } + + while(idxP < lenP && p[idxP] === '*') { + idxP++; + } + + if(idxS === lenS && idxP === lenP) { + return true; + } + + return false; +}; \ No newline at end of file diff --git a/45 Jump Game II.js b/45 Jump Game II.js new file mode 100644 index 0000000..575f437 --- /dev/null +++ b/45 Jump Game II.js @@ -0,0 +1,25 @@ +/** + * @param {number[]} nums + * @return {number} + */ +var jump = function(nums) { + var curMax = 0; + var nJumps = 0; + var i = 0; + var n = nums.length; + + while(curMax < n - 1) { + var lastMax = curMax; + // go through covered area + for(; i <= lastMax; i++) { + curMax = Math.max(curMax, i+nums[i]); + } + nJumps++; + // if cannot make progress in the covered area, give up + if(lastMax === curMax) { + return -1; + } + } + + return nJumps; +}; \ No newline at end of file diff --git a/46 Permutations.js b/46 Permutations.js index 14f1e8c..47a6069 100644 --- a/46 Permutations.js +++ b/46 Permutations.js @@ -1,4 +1,4 @@ -// Leetcode 309 +// Leetcode 46 // Language: Javascript // Problem: https://leetcode.com/problems/permutations/ // Author: Chihung Yu @@ -6,6 +6,34 @@ * @param {number[]} nums * @return {number[][]} */ + +var permute = function(nums) { + var result = []; + generatePermute(nums, [], result); + + return result; +}; + +var generatePermute = function(nums, currentResult, finalResult) { + if(nums.length === 0) { + finalResult.push(currentResult.slice()); + return; + } + + for(var i = 0; i < nums.length; i++) { + var num = nums[i]; + + currentResult.push(num); + var newNums = nums.slice(0, i).concat(nums.slice(i + 1)); + generatePermute(newNums, currentResult, finalResult); + currentResult.pop(); + } +} + +// can be optimized by using an array to keep track of visited elements in the array which ultimately cut down the time slicing array +// consider array is of size n -> n^2 vs n! + + var permute = function(nums) { var result = []; var visited = []; @@ -18,6 +46,7 @@ var permute = function(nums) { var generate = function(nums, index, visited, output, result) { if(nums.length === output.length) { result.push(output.slice()); + return; } for(var i = 0; i < nums.length; i++) { @@ -30,4 +59,31 @@ var generate = function(nums, index, visited, output, result) { } } -} \ No newline at end of file +} + + +// Another clear solution +var permute = function(nums) { + return permuteAux(nums, []); +}; + +var permuteAux = function(nums, partialNums) { + if(nums === null || nums.length === 0) { + return [partialNums]; + } + var listArrays = []; + for(var i = 0; i < nums.length; i++) { + var withoutI = nums.slice(0,i).concat(nums.slice(i + 1, nums.length)); + var partial = partialNums.concat([nums[i]]); + var sol = permuteAux(withoutI, partial); + if(sol.legnth !== 0) { + listArrays = listArrays.concat(sol); + } + } + return listArrays; +}; + + + + + diff --git a/47 Permutations II.js b/47 Permutations II.js new file mode 100644 index 0000000..5bb29fa --- /dev/null +++ b/47 Permutations II.js @@ -0,0 +1,81 @@ +// Given a collection of numbers that might contain duplicates, return all possible unique permutations. + +// For example, +// [1,1,2] have the following unique permutations: +// [ +// [1,1,2], +// [1,2,1], +// [2,1,1] +// ] +// Hide Company Tags LinkedIn Microsoft +// Show Tags +// Hide Similar Problems (M) Next Permutation (M) Permutations (M) Palindrome Permutation II + + +/** + * @param {number[]} nums + * @return {number[][]} + */ +var permuteUnique = function(nums) { + nums.sort((a,b)=> a > b ? 1 : -1); + + var result = []; + var visited = Array(nums.length).fill(false); + generatePermute(nums, 0, [], visited, result); + + return result; +}; + + +var generatePermute = function(nums, step, currentResult, visited, finalResult) { + // Since we might have duplicate and skipped some nums, so the currentResult.length might not equal to nums.length even when we are already done traversing + // if(nums.length === currentResult.length) { + if(step === nums.length) { + finalResult.push(currentResult.slice()); + return; + } + + for(var i = 0; i < nums.length; i++) { + if(!visited[i]) { + // !!! important: nums[i] === nums[i-1] && !visited[i-1] + if(i > 0 && nums[i] === nums[i-1] && !visited[i-1]) { + continue; + } + + visited[i] = true; + var num = nums[i]; + currentResult.push(num); + generatePermute(nums, step + 1, currentResult, visited, finalResult); + currentResult.pop(); + visited[i] = false; + } + } +} + +//Another Solution, similar approach that Permutation.js +var permuteUnique = function(nums) { + return permut(nums.sort(), []); +}; + +var permut = function(nums, partial) { + if(nums.length === 0) { + return [partial]; + } + var listSol = []; + for(var i = 0; i < nums.length; i++) { + var endRepeated = i; + while(endRepeated < nums.length && nums[i] === nums[endRepeated]) { + endRepeated++; + } + + var arrayWithoutI = nums.slice(0,i).concat(nums.slice(i + 1, nums.length)); + var partialSol = partial.concat([nums[i]]); + var sol = permut(arrayWithoutI, partialSol); + if(sol.length > 0){ + listSol = listSol.concat(sol); + } + i = endRepeated - 1; + } + return listSol; +}; + diff --git a/48 Rotate Image.js b/48 Rotate Image.js index 47fe88f..46a0072 100644 --- a/48 Rotate Image.js +++ b/48 Rotate Image.js @@ -1,29 +1,112 @@ +// You are given an n x n 2D matrix representing an image. + +// Rotate the image by 90 degrees (clockwise). + +// Follow up: +// Could you do this in-place? + /** * @param {number[][]} matrix * @return {void} Do not return anything, modify matrix in-place instead. */ var rotate = function(matrix) { - if(matrix === null || matrix.length === 0){ + var row = matrix.length; + + if(row === 0) { return; } - - var len = matrix.length; - - for(var i = 0; i < len - 1; i++){ - for(var j = 0; j < len - i; j++){ - swap(matrix,i,j,len-1-j,len-1-i); + + var col = matrix[0].length; + + // swap them in diagonal + for(var i = 0; i < row; i++) { + for(var j = 0; j < col - i; j++) { + swap(matrix, i, j, row - 1 - j, col - 1 - i); + } + } + + // swap in middle + for(i = 0; i < Math.floor(row/2); i++) { + for(j = 0; j < col; j++) { + swap(matrix, i, j, row - 1 - i, j); } } - - for(i = 0; i < parseInt(len/2); i++){ - for(j = 0; j < len; j++){ - swap(matrix,i,j,len-1-i,j); +}; + +function swap(matrix, x1, y1, x2, y2) { + var tmp = matrix[x1][y1]; + matrix[x1][y1] = matrix[x2][y2]; + matrix[x2][y2] = tmp; +} + +//Clearer Solution +var rotate = function(matrix) { + rotateColumns(matrix); + rotateEachDiagonal(matrix); +}; + +var rotateColumns = function(matrix) { + for(var j = 0; j < matrix.length; j++) { + var low = 0; + var ceil = matrix.length -1; + while(low < ceil) { + swap(matrix, low, j, ceil, j); + low++; + ceil--; + } + } +}; + +var rotateEachDiagonal = function(matrix){ + for(var i = 0; i < matrix.length; i++) { + for(var j = i; j < matrix.length; j++) { + swap(matrix, i, j, j, i); } } }; -var swap = function(matrix,x1,y1,x2,y2){ +var swap = function(matrix, i1, j1, i2, j2) { + var aux = matrix[i1][j1]; + matrix[i1][j1] = matrix[i2][j2]; + matrix[i2][j2] = aux; +}; + + + + +/** + * @param {number[][]} matrix + * @return {void} Do not return anything, modify matrix in-place instead. + */ +var rotate = function(matrix) { + rotateDiagonal(matrix); + rotateRow(matrix); +}; + +var swap = function(matrix, x1, y1, x2, y2) { var temp = matrix[x1][y1]; matrix[x1][y1] = matrix[x2][y2]; matrix[x2][y2] = temp; +} + +var rotateRow = function(matrix) { + for(var i = 0; i < matrix.length; i++) { + var row = matrix[i]; + var start = 0; + var end = matrix[i].length - 1; + + while(start < end) { + swap(matrix, i, start, i, end); + start++; + end--; + } + } +} + +var rotateDiagonal = function(matrix) { + for(var i = 0; i < matrix.length; i++) { + for(var j = i; j < matrix.length; j++) { + swap(matrix, i, j, j, i); + } + } } \ No newline at end of file diff --git a/49 Group Anagrams.js b/49 Group Anagrams.js index e8738de..65e684c 100644 --- a/49 Group Anagrams.js +++ b/49 Group Anagrams.js @@ -1,37 +1,75 @@ +// Given an array of strings, group anagrams together. + +// For example, given: ["eat", "tea", "tan", "ate", "nat", "bat"], +// Return: + +// [ +// ["ate", "eat","tea"], +// ["nat","tan"], +// ["bat"] +// ] +// Note: All inputs will be in lower-case. /** * @param {string[]} strs * @return {string[][]} */ - - - var groupAnagrams = function(strs) { - var hash = {} + var hash = {}; for(var i = 0; i < strs.length; i++) { var str = strs[i]; - var sortedStr = sort(str); - hash[sortedStr] = hash[sortedStr] || []; - hash[sortedStr].push(str); + var key = sort(str); + + hash[key] = hash[key] || []; + hash[key].push(str); } var result = []; - for(i in hash) { - var arr = hash[i].sort(function (a,b) { - return a > b ? 1 : -1; - }); - result.push(arr); + result.push(hash[i]); } + return result; }; + var sort = function(s) { var arr = s.split(''); - arr.sort(function (a,b) { - return a > b ? 1 : -1; - }); + arr.sort((a,b)=> a > b ? 1 : -1); return arr.join(''); -} \ No newline at end of file +} + + + +// Use bucket sort, much faster + +/** + * @param {string[]} strs + * @return {string[][]} + */ +var groupAnagrams = function(strs) { + var hash = {}; + var base = 'a'.charCodeAt(0); + + for(var i = 0; i < strs.length; i++) { + var arr = Array(26).fill(0); + for(var j = 0; j < str.length; j++) { + var code = str[j].charCodeAt(0) - base; + arr[code]++; + } + + var key = arr.join(''); + hash[key] = hash[key] || []; + hash[key].push(strs[i]); + } + + var res = []; + + for(i in hash) { + res.push(hash[i]); + } + + return res; +}; diff --git a/5 Longest Palindromic Substring.js b/5 Longest Palindromic Substring.js index b9f7bd7..deb0ab9 100644 --- a/5 Longest Palindromic Substring.js +++ b/5 Longest Palindromic Substring.js @@ -1,23 +1,37 @@ +// Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring. +// Amazon Microsoft Bloomberg +// Show Tags +// Show Similar Problems + /** * @param {string} s * @return {string} */ + + var longestPalindrome = function(s) { if(s === null || s.length === 0){ return ""; } var result = ""; + + // The reason to multiply by 2 is because + // Palindrome can be in two forms + // 1. abba There will be case which center has two idenitical charachter, + // And there will be maximum 2*n - 1 such case + // 2. aba There will be case which center has only one character + var len = 2*s.length - 1; + var left, right; - for(var i = (2*s.length) - 1; i--;){ - var left = parseInt(i/2); - var right = parseInt(i/2); + for(var i = 0; i < len; i++){ + left = right = parseInt(i/2); if(i%2 === 1){ right++; } - var str = lengthOfPalindrome(s,left,right); + var str = expandFromCenterAndCheckForPalindrome(s,left,right); if(str.length > result.length){ result = str; @@ -27,7 +41,43 @@ var longestPalindrome = function(s) { }; -var lengthOfPalindrome = function(s, left, right){ +// other implementation + +var longestPalindrome = function(s) { + if(s === null || s.length === 0){ + return ""; + } + + var result = ""; + var len = s.length; + var left, right; + + for(var i = 0; i < len; i++){ + left = right = i; + + var str = expandFromCenterAndCheckForPalindrome(s,left,right); + if(str.length > result.length){ + result = str; + } + var str = expandFromCenterAndCheckForPalindrome(s,left,right + 1); + if(str.length > result.length){ + result = str; + } + } + return result; +}; + + + +var expandFromCenterAndCheckForPalindrome = function(s, left, right){ + // in the case where left !== right + // that's the case "abba" + // which it checks for if b === b then a === a + + // in the case where left === right + // that's the case "aba" + // which it check if b === b as left === right + // then a === a while(left >= 0 && right < s.length && s[left] === s[right]){ left--; right++; diff --git a/51 N-Queens.js b/51 N-Queens.js index f6e91e9..f710e95 100644 --- a/51 N-Queens.js +++ b/51 N-Queens.js @@ -40,6 +40,10 @@ var helper = function(n, row, columnForRow, res){ var isValid = function(row, columnForRow){ for(var i = 0; i < row; i++){ + // 1. don't have to worry about values on the same column since it will onnly be set once + // 2. same column, columnForRow[row] === columnForRow[i] + // 3. checking both left and right diagonal, Math.abs(columnForRow[row] - columnForRow[i]) === row - i + // Math.abs(columnForRow[row] - columnForRow[i]) is checking both left and right diagonal if(columnForRow[row] === columnForRow[i] || Math.abs(columnForRow[row] - columnForRow[i]) === row - i){ return false; } diff --git a/532. K-diff Pairs in an Array.js b/532. K-diff Pairs in an Array.js new file mode 100644 index 0000000..03e75bc --- /dev/null +++ b/532. K-diff Pairs in an Array.js @@ -0,0 +1,24 @@ +var findPairs = function(nums, k) { + if(nums.length === 0 || k < 0) { + return 0; + } + var dict = {}; + var count = 0; + + nums.sort(function(a,b){ return a - b }); + for(var i = 0; i < nums.length; i++) { + var number = nums[i]; + dict[number] = (dict[number] === undefined)? 1 : dict[number] += dict[number]; + } + for(var numb in dict) { + numb = parseInt(numb); + if(k === 0) { + if(dict[numb] > 1) { + count++; + } + } else if(dict[numb + k] !== undefined){ + count++; + } + } + return count; +}; diff --git a/54 Spiral Matrix.js b/54 Spiral Matrix.js index c61f75e..76d20db 100644 --- a/54 Spiral Matrix.js +++ b/54 Spiral Matrix.js @@ -1,3 +1,19 @@ +// Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order. + +// For example, +// Given the following matrix: + +// [ +// [ 1, 2, 3 ], +// [ 4, 5, 6 ], +// [ 7, 8, 9 ] +// ] +// You should return [1,2,3,6,9,8,7,4,5]. + +// Hide Company Tags Microsoft Google Uber +// Hide Tags Array +// Hide Similar Problems (M) Spiral Matrix II + /** * @param {number[][]} matrix * @return {number[]} diff --git a/55 Jump Game.js b/55 Jump Game.js index a31f2f4..1433dc6 100644 --- a/55 Jump Game.js +++ b/55 Jump Game.js @@ -11,6 +11,5 @@ var canJump = function(nums) { } numLeft = Math.max(nums[i], numLeft); } - - return numLeft >= 0; + return true; }; \ No newline at end of file diff --git a/56. Merge Intervals.js b/56. Merge Intervals.js new file mode 100644 index 0000000..86b5d0c --- /dev/null +++ b/56. Merge Intervals.js @@ -0,0 +1,47 @@ +// Given a collection of intervals, merge all overlapping intervals. + +// For example, +// Given [1,3],[2,6],[8,10],[15,18], +// return [1,6],[8,10],[15,18]. + +// Hide Company Tags LinkedIn Google Facebook Twitter Microsoft Bloomberg Yelp +// Hide Tags Array Sort +// Hide Similar Problems (H) Insert Interval (E) Meeting Rooms (M) Meeting Rooms II + + /** + * Definition for an interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * } + */ + /** + * @param {Interval[]} intervals + * @return {Interval[]} + */ + + + var merge = function(intervals) { + var res = []; + + intervals.sort((i1, i2) => i1.start > i2.start ? 1 : -1 ); + + if(intervals.length) { + res.push(intervals[0]); + } + + for(var i = 1; i < intervals.length; i++) { + var interval = intervals[i]; + var last = res.pop(); + + if(interval.start > last.end) { + res.push(last); + res.push(interval); + } else { + last.end = Math.max(last.end, interval.end); + res.push(last); + } + } + + return res; + }; \ No newline at end of file diff --git a/57. Insert Interval.js b/57. Insert Interval.js new file mode 100644 index 0000000..58d8469 --- /dev/null +++ b/57. Insert Interval.js @@ -0,0 +1,62 @@ +// Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). + +// You may assume that the intervals were initially sorted according to their start times. + +// Example 1: +// Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9]. + +// Example 2: +// Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16]. + +// This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10]. + +// Hide Company Tags LinkedIn Google Facebook +// Show Tags +// Show Similar Problems + + +/** + * Definition for an interval. + * function Interval(start, end) { + * this.start = start; + * this.end = end; + * } + */ +/** + * @param {Interval[]} intervals + * @param {Interval} newInterval + * @return {Interval[]} + */ + +// http://bangbingsyb.blogspot.com/2014/11/leetcode-insert-interval.html +var insert = function(intervals, newInterval) { + var result = []; + // Easier to consider if two sections are not overlapped + // [s1, e1] [s2, e2] --> e2 < s1 or e1 < s2 + // once merged when two sections are overlapped, [min(s1,s2), max(e1,e2)] + + var isInsert = false; + + for(var i = 0; i < intervals.length; i++) { + var interval = intervals[i]; + + if(isInsert) { + result.push(interval); + } else if(newInterval.end < interval.start) { // insertion before the sorted interval + result.push(newInterval); + result.push(interval); + isInsert = true; + } else if(interval.end < newInterval.start) { // no overlap at all + result.push(interval); + } else { + newInterval.start = Math.min(newInterval.start, interval.start); + newInterval.end = Math.max(newInterval.end, interval.end); + } + } + + if(!isInsert) { // insertion at the very end; + result.push(newInterval); + } + + return result; +}; \ No newline at end of file diff --git a/59 Spiral Matrix II.js b/59 Spiral Matrix II.js index a0788d2..a1694d1 100644 --- a/59 Spiral Matrix II.js +++ b/59 Spiral Matrix II.js @@ -1,40 +1,58 @@ +// Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order. + +// For example, +// Given n = 3, + +// You should return the following matrix: +// [ +// [ 1, 2, 3 ], +// [ 8, 9, 4 ], +// [ 7, 6, 5 ] +// ] +// Hide Tags Array +// Hide Similar Problems (M) Spiral Matrix + + + /** * @param {number} n * @return {number[][]} */ - var generateMatrix = function(n) { - var m = []; - for(var i = 0; i < n; i++){ - m.push([]); + var matrix = []; + for(var i = 0; i < n; i++) { + matrix.push([]); } - - var level = parseInt(n/2); + var x = 0; + var y = 0; var count = 1; - for(var l = 0; l < level; l++){ - var x = l; - var y = l; - for(x = l; x < n - 1 - l; x++){ - m[y][x] = count++; + while(0 < n) { + if(n === 1) { + matrix[x][y] = count; + break; } - for(y = l; y < n - 1 - l; y++){ - m[y][x] = count++; + for(i = 0; i < n - 1; i++) { + matrix[x][y++] = count++; } - for(; x > l; x--){ - m[y][x] = count++; + for(i = 0; i < n - 1; i++) { + matrix[x++][y] = count++; } - for(; y > l; y--){ - m[y][x] = count++; + for(i = 0; i < n - 1; i++) { + matrix[x][y--] = count++; } + + for(i = 0; i < n - 1; i++) { + matrix[x--][y] = count++; + } + + x++; + y++; + n -= 2; } - if(n%2 === 1){ - m[level][level] = count; - } - - return m; -} \ No newline at end of file + return matrix; +}; \ No newline at end of file diff --git a/65 Valid Number.js b/65 Valid Number.js new file mode 100644 index 0000000..f77f915 --- /dev/null +++ b/65 Valid Number.js @@ -0,0 +1,30 @@ +/** + * @param {string} s + * @return {boolean} + */ + + + +// valid cases +// 9 +// .9 +// 9. +// 0.9 +// 9e10 +// 9e-10 + +// invalid case +// . +// ab +// 9ea10 +// 9e +// e9 +// .e1 + + + +// cannot use (\d*\.?\d*)\d+ + +var isNumber = function(s) { + return !!s.match(/^\s*[+-]?(\d+\.\d+|\d+\.|\.\d+|\d+)(\e[+-]?\d+)?\s*$/); +}; \ No newline at end of file diff --git a/66 Plus One.js b/66 Plus One.js index 0d1c6cb..9dae196 100644 --- a/66 Plus One.js +++ b/66 Plus One.js @@ -2,6 +2,35 @@ * @param {number[]} digits * @return {number[]} */ + +// Time complexity : \mathcal{O}(N)O(N) since it's not more than one pass along the input list. + +// Space complexity : \mathcal{O}(1)O(1). +var plusOne = function(digits) { + var carry = 1; + for(var i = digits.length - 1; i > -1; i--) { + var d = digits[i]; + var sum = d + carry; + if (sum === 10) { + digits[i] = 0; + carry = 1; + } else { + digits[i] = sum; + carry = 0; // can directly return since it will not trigger the carry unshift at the end. + break; + } + } + + if (carry === 1) { + digits.unshift(carry); + } + + return digits; +}; + + + + var plusOne = function(digits) { for(var i = digits.length; i--;){ digits[i] = 1 + digits[i]; diff --git a/67 Add Binary.js b/67 Add Binary.js index 3685410..9a30aa6 100644 --- a/67 Add Binary.js +++ b/67 Add Binary.js @@ -1,3 +1,15 @@ +// Given two binary strings, return their sum (also a binary string). + +// For example, +// a = "11" +// b = "1" +// Return "100". + +// Hide Company Tags Facebook +// Hide Tags Math String +// Hide Similar Problems (M) Add Two Numbers (M) Multiply Strings (E) Plus One + + /** * @param {string} a * @param {string} b @@ -6,19 +18,20 @@ var addBinary = function(a, b) { var lenA = a.length; var lenB = b.length; + var ai = 0; + var bi = 0; + var sum = ''; var carry = 0; - var result = ''; - var maxLen = Math.max(lenA, lenB); - - for(var i = 0; i < maxLen; i++){ - - var p = parseInt(a[lenA - i - 1] || '0'); - var q = parseInt(b[lenB - i - 1] || '0'); - - var tmp = p + q + carry; - result = tmp%2 + result; - carry = parseInt(tmp/2); + while(ai < lenA || bi < lenB) { + var valA = ai < lenA ? parseInt(parseInt(a[lenA - 1 - ai])) : 0; + var valB = bi < lenB ? parseInt(parseInt(b[lenB - 1 - bi])) : 0; + var val = valA + valB + carry; + var rem = val%2; + carry = val > 1 ? 1 : 0; + sum = rem + sum; + ai++; + bi++; } - return (carry === 0) ? result : '1' + result; + return carry > 0 ? carry + sum : sum; }; \ No newline at end of file diff --git a/68 Text Justification.js b/68 Text Justification.js new file mode 100644 index 0000000..ff6446e --- /dev/null +++ b/68 Text Justification.js @@ -0,0 +1,96 @@ +// Given an array of words and a length L, format the text such that each line has exactly L characters and is fully (left and right) justified. + +// You should pack your words in a greedy approach; that is, pack as many words as you can in each line. Pad extra spaces ' ' when necessary so that each line has exactly L characters. + +// Extra spaces between words should be distributed as evenly as possible. If the number of spaces on a line do not divide evenly between words, the empty slots on the left will be assigned more spaces than the slots on the right. + +// For the last line of text, it should be left justified and no extra space is inserted between words. + +// For example, +// words: ["This", "is", "an", "example", "of", "text", "justification."] +// L: 16. + +// Return the formatted lines as: +// [ +// "This is an", +// "example of text", +// "justification. " +// ] +// Note: Each word is guaranteed not to exceed L in length. +// http://bangbingsyb.blogspot.com/2014/11/leetcode-text-justification.html +/** + * @param {string[]} words + * @param {number} maxWidth + * @return {string[]} + */ +var fullJustify = function(words, maxWidth) { + var result = []; + var start = 0; + var end = -1; + var currentWordsLen = 0; + var i = 0; + + while(i < words.length) { + if(words[i].size > maxWidth) { + return result; + } + + var newLen = currentWordsLen + (end - start + 1) + words[i].length; // current words len + their spaces + new word + + if(newLen <= maxWidth) { // words[i] can fit in the current line + end = i; + currentWordsLen += words[i].length; + i++; + } else { + var line = createLine(words, maxWidth, start, end, currentWordsLen, false); + result.push(line); + start = i; + end = i - 1; + currentWordsLen = 0; + } + } + + var lastLine = createLine(words, maxWidth, start, end, currentWordsLen, true); + result.push(lastLine); + return result; +}; + + +function createLine(words, maxWidth, start, end, currentWordsLen, isLast) { + var result = ''; + if(start < 0 || end >= words.length) { + return result; + } + + result += words[start]; // consume the first word + var numberOfWords = end - start + 1; // number of words to insert in this line + + // special case: one word or last line - left justified + if(numberOfWords === 1 || isLast) { + for(var i = start + 1; i <= end; i++) { // start from start + 1 since we already append the first word + result += (" " + words[i]); + } + + var remainingSpaces = maxWidth - currentWordsLen - (numberOfWords - 1); + for(i = 0; i < remainingSpaces; i++) { + result += ' '; + } + + return result; + } + + var k = parseInt((maxWidth - currentWordsLen)/(numberOfWords - 1)); + var m = (maxWidth - currentWordsLen)%(numberOfWords - 1); + + for(i = start + 1; i <= end; i++) { // start from start + 1 since we already append the first word + var nspace = i - start <= m ? k + 1: k; + + for(var j = 0; j < nspace; j++) { + result += ' '; + } + + result += words[i]; + } + + return result; +} \ No newline at end of file diff --git a/681 Next Closest Time .js b/681 Next Closest Time .js new file mode 100644 index 0000000..41a2ef9 --- /dev/null +++ b/681 Next Closest Time .js @@ -0,0 +1,75 @@ +// Given a time represented in the format "HH:MM", form the next closest time by reusing the current digits. There is no limit on how many times a digit can be reused. + +// You may assume the given input string is always valid. For example, "01:34", "12:09" are all valid. "1:34", "12:9" are all invalid. + +// Example 1: + +// Input: "19:34" +// Output: "19:39" +// Explanation: The next closest time choosing from digits 1, 9, 3, 4, is 19:39, which occurs 5 minutes later. It is not 19:33, because this occurs 23 hours and 59 minutes later. +// Example 2: + +// Input: "23:59" +// Output: "22:22" +// Explanation: The next closest time choosing from digits 2, 3, 5, 9, is 22:22. It may be assumed that the returned time is next day's time since it is smaller than the input time numerically. + + + + +// Approach #1: Simulation [Accepted] +// Intuition and Algorithm + +// Simulate the clock going forward by one minute. Each time it moves forward, if all the digits are allowed, then return the current time. + +// The natural way to represent the time is as an integer t in the range 0 <= t < 24 * 60. Then the hours are t / 60, the minutes are t % 60, and each digit of the hours and minutes can be found by hours / 10, hours % 10 etc. + +/** + * @param {string} time + * @return {string} + */ +var nextClosestTime = function(time) { + let cur = 60 * parseInt(time.substring(0, 2)); + cur += parseInt(time.substring(3)); + const allowed = new Set(); + + for(var i = 0; i < time.length; i++) { + if (time[i] !== ':') { + allowed.add(parseInt(time[i])); + } + } + + while(true) { + cur = (cur + 1) % (24*60); + var curTime = [ + Math.floor(cur / 60 / 10), // hour 24 -> 2 + Math.floor(cur / 60) % 10, // hour 24 -> 4 + Math.floor((cur % 60) / 10), // minutes 59 -> 5 + cur % 60 % 10, // minutes 59 -> 9 + ]; + + for(i = 0; i < curTime.length; i++) { + var t = curTime[i]; + if (!allowed.has(t)) { + break; + } + if (i === curTime.length - 1) { + let hour = Math.floor(cur / 60); + let min = cur % 60; + + if (hour < 10) { + hour = '0' + hour; + } else { + hour = '' + hour; + } + + if (min < 10) { + min = '0' + min; + } else { + min = '' + min; + } + + return hour + ':' + min; + } + } + } +}; \ No newline at end of file diff --git a/69 Sqrt(x).js b/69 Sqrt(x).js new file mode 100644 index 0000000..57c1446 --- /dev/null +++ b/69 Sqrt(x).js @@ -0,0 +1,58 @@ +/** +Implement int sqrt(int x). + +Compute and return the square root of x. +*/ +/** + * @param {number} x + * @return {number} + */ +var mySqrt = function(x) { + var start = 1, + end = x, + mid; + + if (x === 0) { + return 0; + } + + while (start + 1 < end) { + mid = start + parseInt((end - start) / 2); + + if (mid * mid <= x) { + start = mid; + } else { + end = mid; + } + } + + return start; +}; + + + +// http://www.cs.wustl.edu/~kjg/CS101_SP97/Notes/SquareRoot/sqrt.html + +var mySqrtWithPrecision = function(digit, precision) { + // Set initial guess to 1 + var guess = 1; + var closeEnoughPrecision = Math.pow(0.1, precision + 1); + + while(true) { + // difference between guess and real value + // e.g. 5's sqrt = 2.236 + // val = x*x sqrt = val/x + // if we guess 3 as the sqrt of 5 -> 5/3 = 1.666 the difference between 3 and 1.6666 is 1.3333 and is way off + // as it should be x*x = 5 and x here is 2.236 + var diff = Math.abs(guess - digit/guess); + + if(diff > closeEnoughPrecision) { + // Better guess will be (3 + 1.66666)/2 => 2.3333 + guess = (guess + digit/guess)/2; + } else { + break; + } + } + + return guess; +} \ No newline at end of file diff --git a/70 Climbing Stairs.js b/70 Climbing Stairs.js index 3248c05..33803ac 100644 --- a/70 Climbing Stairs.js +++ b/70 Climbing Stairs.js @@ -1,22 +1,24 @@ +// You are climbing a stair case. It takes n steps to reach to the top. + +// Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? + /** * @param {number} n * @return {number} */ var climbStairs = function(n) { - if(n <= 0){ - return 0; - } - if(n === 1){ - return 1; - } - - var uniqueways = []; - uniqueways[0] = 1; - uniqueways[1] = 1; + var n1 = 1; + var n2 = 1; - for(var i = 2; i <= n; i++){ - uniqueways[i] = uniqueways[i-1] + uniqueways[i-2]; + + // n1 and n2 stands for how many ways it can reach n taking one step or two steps, such as n - 1 and n - 2 + for(var i = 2; i <= n; i++) { + var ways = n1 + n2; + n1 = n2; + n2 = ways; } + + - return uniqueways[n] -}; + return n2; +}; \ No newline at end of file diff --git a/71 Simplify Path.js b/71 Simplify Path.js index 69141e7..5e28f20 100644 --- a/71 Simplify Path.js +++ b/71 Simplify Path.js @@ -1,21 +1,25 @@ +// Given an absolute path for a file (Unix-style), simplify it. + +// For example, +// path = "/home/", => "/home" +// path = "/a/./b/../../c/", => "/c" + /** * @param {string} path * @return {string} */ var simplifyPath = function(path) { var arr = path.split('/'); - var stack = []; + var result = []; - for(var i = 0; i < arr.length; i++){ - var c = arr[i]; - - if(c === '..'){ - stack.pop(); - } else if(c !== '' && c !== '.' && c !== '/'){ - stack.push(c); + for(var i = 0; i < arr.length; i++) { + var p = arr[i]; + if(p === '..') { + result.pop(); + } else if(p !== '' && p !== '.') { + result.push(p); } } - var result = stack.join('/'); - return '/' + result; + return '/' + result.join('/'); }; \ No newline at end of file diff --git a/72 Edit Distance.js b/72 Edit Distance.js index ffc2dd4..f6099c7 100644 --- a/72 Edit Distance.js +++ b/72 Edit Distance.js @@ -1,3 +1,17 @@ +// reference: https://www.youtube.com/watch?v=We3YDTzNXEk + +// Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.) + +// You have the following 3 operations permitted on a word: + +// a) Insert a character +// b) Delete a character +// c) Replace a character +// Hide Tags Dynamic Programming String +// Hide Similar Problems (M) One Edit Distance + + + /** * @param {string} word1 * @param {string} word2 diff --git a/74 Search a 2D Matrix.js b/74 Search a 2D Matrix.js index 28b7549..83adad9 100644 --- a/74 Search a 2D Matrix.js +++ b/74 Search a 2D Matrix.js @@ -1,3 +1,23 @@ +// Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: + +// Integers in each row are sorted in ascending from left to right. +// Integers in each column are sorted in ascending from top to bottom. +// For example, + +// Consider the following matrix: + +// [ +// [1, 4, 7, 11, 15], +// [2, 5, 8, 12, 19], +// [3, 6, 9, 16, 22], +// [10, 13, 14, 17, 24], +// [18, 21, 23, 26, 30] +// ] +// Given target = 5, return true. + +// Given target = 20, return false. + + /** * @param {number[][]} matrix * @param {number} target @@ -5,48 +25,23 @@ */ var searchMatrix = function(matrix, target) { - if(matrix === null || matrix.length === 0 || matrix[0].length === 0){ - return false; - } - - if(target < matrix[0][0]){ // Key base condition + if(matrix === null || matrix.length === 0 || matrix[0].length === 0) { return false; } - var rows = matrix.length - 1; - var cols = matrix[0].length - 1; + var rows = matrix.length; + var cols = matrix[0].length; - if(target > matrix[rows][cols]){ // Key base condition - return false; - } + var y = cols - 1; - var start = 0; - var end = rows; - while(start <= end){ - var mid = start + parseInt((end - start)/2); - if(matrix[mid][0] === target){ - return true; - } else if(matrix[mid][0] < target){ - start = mid + 1; - } else { // Utilize else rather than define all conditions - end = mid - 1; + for(var x = 0; x < rows; x++) { + while(y && target < matrix[x][y]) { + y--; } - } - - var targetRow = end; - start = 0; - end = cols ; - - while(start <= end){ - mid = start + parseInt((end - start)/2); - - if(matrix[targetRow][mid] === target){ + if(matrix[x][y] === target) { return true; - } else if(matrix[targetRow][mid] < target){ - start = mid + 1; - } else { // Utilize else rather than define all conditions - end = mid - 1; } } + return false; }; \ No newline at end of file diff --git a/75 Sort Colors.js b/75 Sort Colors.js index 7a26698..1bd8b54 100644 --- a/75 Sort Colors.js +++ b/75 Sort Colors.js @@ -1,29 +1,66 @@ +// Given an array with n objects colored red, white or blue, sort them so that objects of the same color are adjacent, with the colors in the order red, white and blue. + +// Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively. + +// Note: +// You are not suppose to use the library's sort function for this problem. + +// click to show follow up. + +// Hide Company Tags Pocket Gems Microsoft Facebook +// Hide Tags Array Two Pointers Sort +// Hide Similar Problems (M) Sort List (M) Wiggle Sort (M) Wiggle Sort II + /** * @param {number[]} nums * @return {void} Do not return anything, modify nums in-place instead. */ +// var sortColors = function(nums) { +// var redIndex = 0; +// var blueIndex = nums.length - 1; +// var red = 0; +// var blue = 2; + +// for(var i = 0; i <= blueIndex; i++) { +// if(nums[i] === red) { +// swap(nums, redIndex, i); +// redIndex++; +// } else if(nums[i] === blue) { +// swap(nums, blueIndex, i); +// blueIndex--; +// i--; +// } +// } +// }; + +// function swap(arr, i, j) { +// if(i === j) { +// return; +// } +// var tmp = arr[i]; +// arr[i] = arr[j]; +// arr[j] = tmp; +// } + var sortColors = function(nums) { - var redIndex = 0; - var blueIndex = nums.length - 1; - var i = 0 + var redIdx = 0; + var blueIdx = nums.length - 1; + var i = 0; - while(i <= blueIndex){ - if(nums[i] === 0){ - swap(nums, i, redIndex); - i++; // [!!!] if swap with latter colors do not i++ - redIndex++; - } else if(nums[i] === 2){ - swap(nums, i, blueIndex); - blueIndex--; + while(i <= blueIdx) { + if(nums[i] === 0) { + swap(nums, i++, redIdx++); + } else if(nums[i] === 2) { + swap(nums, i, blueIdx--); } else { - i++; + i++; } } -}; - -var swap = function(arr, i, j){ - var temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; -} \ No newline at end of file + + function swap(nums, i, j) { + var tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + } +}; \ No newline at end of file diff --git a/76 Minimum Window Substring.js b/76 Minimum Window Substring.js new file mode 100644 index 0000000..e18e98b --- /dev/null +++ b/76 Minimum Window Substring.js @@ -0,0 +1,148 @@ +// Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n). + +// For example, +// S = "ADOBECODEBANC" +// T = "ABC" +// Minimum window is "BANC". + +// Note: +// If there is no such window in S that covers all characters in T, return the empty string "". + +// If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S. + +// Hide Company Tags LinkedIn Uber Facebook +// Hide Tags Hash Table Two Pointers String +// Hide Similar Problems + + +/** + * @param {string} s + * @param {string} t + * @return {string} + */ + +// reference: http://www.cnblogs.com/TenosDoIt/p/3461301.html +var minWindow = function(s, t) { + var lenS = s.length; + var lenT = t.length; + var queue = []; + var tRequireCount = {}; // string T required count + var tFoundCount = {}; // string T found count + var hasFound = 0; + var windowBeg = -1; + var windowEnd = lenS; + + for(var i = 0; i < lenT; i++) { + // init tFoundCount to all 0s + tFoundCount[t[i]] = 0; + // init tRequireCount to count of that character in t + tRequireCount[t[i]] = tRequireCount[t[i]] || 0; + tRequireCount[t[i]]++; + } + + for(i = 0; i < lenS; i++) { + // cannot use tRequireCount[s[i]] !== 0 since tRequireCount[s[i]] might be undefined + if(tRequireCount[s[i]] > 0) { + // use queue to skip a lot of redudant character + // minWindow('aeeeeeebceeeeaeeedcb', 'abc'); + // queue will contain index + // 1st round: [ 0, 7, 8 ] and then get rid of character at 0 + // 2nd round: [ 7, 8, 13 ] and get rid of character at 7 + // 3rd round: [ 8, 13, 18, 19 ] + queue.push(i); + tFoundCount[s[i]]++; + + // if found count is over require count, we don't need those extra, so don't record it to hasFound + if(tFoundCount[s[i]] <= tRequireCount[s[i]]) { + // hasFound is used as a flag for knowing where we should check against T string and when we should start reducing the range + // for example + // minWindow('aaaaebceeeeaeeedcb', 'abc'); + // at index 5 where s[i] is e, hasFound is 1 and tFoundCount['a'] is 4, queue=[0,1,2,3] + // when we arrive at index 7 where s[i] is c, has found is now 3 and is equal to lenT + // now we can start reducing the range all the way from index 0(a) to index 7(c) to index 3(a) to index 7 (c) which will give us the min + hasFound++; + } + + // when the current location which is in queue + if(hasFound === lenT) { + var k; + + do { + k = queue.shift(); + tFoundCount[s[k]]--; + } while(tFoundCount[s[k]] >= tRequireCount[s[k]]); + // moving to the minimum window location + + if(windowEnd - windowBeg > i - k) { + windowBeg = k; + windowEnd = i; + // window will be in + // 1st round 0 8 + // 2nd round 7 13 + } + // since i must be the last match that leads to hasFound === lenT + hasFound--; + } + } + } + + return windowBeg !== -1 ? s.substring(windowBeg, windowEnd + 1) : ''; +}; + + + +/** + * @param {string} s + * @param {string} t + * @return {string} + */ +var minWindow = function(s, t) { + var lenS = s.length; + var lenT = t.length; + var tCharToFoundCount = {}; + var tCharToRequiredCount = {}; + + for(var i = 0; i < lenT; i++) { + var c = t[i]; + tCharToFoundCount[c] = 0; + tCharToRequiredCount[c] = tCharToRequiredCount[c] || 0; + tCharToRequiredCount[c]++; + } + + var windowBeg = -1; + var windowEnd = lenS; + var queue = []; + var hasFound = 0; + for(i = 0; i < lenS; i++) { + c = s[i]; + // skip unneeded char + if (tCharToRequiredCount[c] !== 0) { + tCharToFoundCount[c]++; + queue.push(i); + + if (tCharToFoundCount[c] <= tCharToRequiredCount[c]) { + hasFound++; + } + + if (hasFound === lenT) { + var k; + + do { + k = queue.shift(); + tCharToFoundCount[s[k]]--; + } while(tCharToFoundCount[s[k]] >= tCharToRequiredCount[s[k]]); + + if (windowEnd - windowBeg > i - k) { + windowBeg = k; + windowEnd = i; + } + + hasFound--; + } + + + } + } + + return windowBeg !== -1 ? s.substring(windowBeg, windowEnd + 1) : ''; +}; \ No newline at end of file diff --git a/77 Combinations.js b/77 Combinations.js index a3a951b..b69d858 100644 --- a/77 Combinations.js +++ b/77 Combinations.js @@ -1,3 +1,20 @@ +// Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. + +// For example, +// If n = 4 and k = 2, a solution is: + +// [ +// [2,4], +// [3,4], +// [2,3], +// [1,2], +// [1,3], +// [1,4], +// ] +// Hide Tags Backtracking +// Hide Similar Problems (M) Combination Sum (M) Permutations + + /** * @param {number} n * @param {number} k diff --git a/78 Subsets.js b/78 Subsets.js new file mode 100644 index 0000000..7540086 --- /dev/null +++ b/78 Subsets.js @@ -0,0 +1,76 @@ +// Given a set of distinct integers, nums, return all possible subsets. + +// Note: The solution set must not contain duplicate subsets. + +// For example, +// If nums = [1,2,3], a solution is: + +// [ +// [3], +// [1], +// [2], +// [1,2,3], +// [1,3], +// [2,3], +// [1,2], +// [] +// ] + + +/** + * @param {number[]} nums + * @return {number[][]} + */ +var subsets = function(nums) { + var result = []; + generate(nums, 0, [], result); + return result; +}; + +var generate = function(nums, index, cur, result) { + if(index === nums.length) { + result.push(cur.slice()); + return + } + + generate(nums, index + 1, cur, result); + cur.push(nums[index]); + generate(nums, index + 1, cur, result); + cur.pop(); +} + + + +// second try +var subsets = function(nums) { + var res = [[]]; + + function generate(nums, i, cur, res) { + for(; i < nums.length; i++) { + cur.push(nums[i]); + res.push(cur.slice()); + generate(nums, i + 1, cur, res); + cur.pop(); + } + } + + generate(nums, 0, [], res); + return res; +}; + +// Third solution +var subsets = function(nums) { + var results = []; + combine(nums, 0, [], results); + return results; +} + +var combine = function(nums, index, partial, results) { + if(index === nums.length) { + results.push(partial); + return; + } + + combine(nums, index + 1, partial, results); + combine(nums, index + 1, partial.concat([nums[index]]), results); +} diff --git a/79 Word Search.js b/79 Word Search.js new file mode 100644 index 0000000..589eabd --- /dev/null +++ b/79 Word Search.js @@ -0,0 +1,60 @@ +// Given a 2D board and a word, find if the word exists in the grid. + +// The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once. + +// For example, +// Given board = + +// [ +// ['A','B','C','E'], +// ['S','F','C','S'], +// ['A','D','E','E'] +// ] +// word = "ABCCED", -> returns true, +// word = "SEE", -> returns true, +// word = "ABCB", -> returns false. +// Hide Company Tags Microsoft Bloomberg Facebook +// Hide Tags Array Backtracking +// Hide Similar Problems (H) Word Search II + + +var exist = function(board, word) { + var hash = {}; + + for(var i = 0; i < board.length; i++) { + for(var j = 0; j < board[0].length; j++) { + if(dfs(board, word, 0, i, j)) { + return true; + } + } + } + + function dfs(board, word, w, i, j) { + var key = i + ',' + j; + if(hash[key]) { + return false; + } + + if(w === word.length) { + return true; + } + + if(i < 0 || i >= board.length || j < 0 || j >= board[0].length) { + return false; + } + + var result = false; + + if(word[w] === board[i][j]) { + hash[key] = true; + + result = dfs(board, word, w + 1, i+1, j) || dfs(board, word, w + 1, i-1, j) || dfs(board, word, w + 1, i, j+1) || dfs(board, word, w + 1, i, j-1); + + hash[key] = false; + } + + return result + } + + return false; +}; \ No newline at end of file diff --git a/8 String to Integer (atoi).js b/8 String to Integer (atoi).js index d04dde8..f981829 100644 --- a/8 String to Integer (atoi).js +++ b/8 String to Integer (atoi).js @@ -1,24 +1,52 @@ +// Implement atoi to convert a string to an integer. + +// Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases. + +// Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front. /** * @param {string} str * @return {number} */ var myAtoi = function(str) { + var num = 0; + var baseCharCode = '0'.charCodeAt(0); + var sign = 1; - var val = parseInt(str) - if(str === null || str.length === 0 || isNaN(val)){ - return 0; + str = str.trim(); + + if(str[0] === '+' || str[0] === '-') { + + if(str[0] === '-') { + sign = -1; + } + + str = str.substring(1); + } + + for(var i = 0; i < str.length; i++) { + var c = str[i]; + var charCode = c.charCodeAt(0) - baseCharCode; + + if(0 <= charCode && charCode <= 9) { + num *= 10; + num += charCode; + } else { + break; + } } - var maxNegInt = -Math.pow(2,31); var maxInt = Math.pow(2,31) - 1; + var minNegInt = -Math.pow(2,31); + + num = sign*num; - if(val > 0 && val > maxInt){ + if(0 < num && maxInt < num) { return maxInt; } - if(val < 0 && val < maxNegInt){ - return maxNegInt; + if(num < 0 && num < minNegInt) { + return minNegInt; } - return val; + return num; }; \ No newline at end of file diff --git a/80 Remove Duplicates from Sorted Array II.js b/80 Remove Duplicates from Sorted Array II.js index 731b272..1de97ca 100644 --- a/80 Remove Duplicates from Sorted Array II.js +++ b/80 Remove Duplicates from Sorted Array II.js @@ -1,25 +1,39 @@ +// Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length. + +// Do not allocate extra space for another array, you must do this in place with constant memory. + +// For example, +// Given input array nums = [1,1,2], + +// Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn't matter what you leave beyond the new length. + +// Hide Company Tags Microsoft Bloomberg Facebook +// Hide Tags Array Two Pointers +// Hide Similar Problems (E) Remove Element + + /** * @param {number[]} nums * @return {number} */ var removeDuplicates = function(nums) { - var n = nums.length; - var index = 0; var oc = 1; + var sorted = 0; for(var i = 1; i < nums.length; i++) { - if(nums[index] === nums[i]) { + if(nums[i] === nums[sorted]) { if(oc === 2) { continue; } + oc++; } else { oc = 1; } - index++; - nums[index] = nums[i]; + sorted++; + nums[sorted] = nums[i]; } - return index + 1; + return sorted + 1; }; \ No newline at end of file diff --git a/81 Search in Rotated Sorted Array II.js b/81 Search in Rotated Sorted Array II.js index 361c6f2..433e5dd 100644 --- a/81 Search in Rotated Sorted Array II.js +++ b/81 Search in Rotated Sorted Array II.js @@ -1,3 +1,15 @@ +// Follow up for "Search in Rotated Sorted Array": +// What if duplicates are allowed? + +// Would this affect the run-time complexity? How and why? + +// Write a function to determine if a given target is in the array. + +// Hide Tags Array Binary Search +// Hide Similar Problems (H) Search in Rotated Sorted Array + + + /** * @param {number[]} nums * @param {number} target @@ -6,30 +18,31 @@ var search = function(nums, target) { var start = 0; var end = nums.length -1; - + while(start <= end){ - var mid = start + parseInt((end - start)/2); - - if(nums[mid] === target){ + var mid = parseInt((end + start)/2); + + if(nums[mid] === target ){ return true; } - - if(nums[start] < nums[mid]){ - if(target >= nums[start] && target < nums[mid]){ // normal order part + + if(nums[start] === nums[mid]) { + start++; + } else if(nums[start] < nums[mid]){ // left part sorted + if(target >= nums[start] && target < nums[mid]){ end = mid - 1; } else { start = mid + 1; } - } else if(nums[mid] < nums[start]) { - if(target <= nums[end] && target > nums[mid]){ // normal order part + } else { //right part sorted + if(target <= nums[end] && target > nums[mid]){ // normal order part start = mid + 1; } else { end = mid -1; } - } else { - start++; } } - + return false; -}; \ No newline at end of file +}; + diff --git a/84 Largest Rectangle in Histogram.js b/84 Largest Rectangle in Histogram.js new file mode 100644 index 0000000..710a9c0 --- /dev/null +++ b/84 Largest Rectangle in Histogram.js @@ -0,0 +1,64 @@ +// Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram. + + +// Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3]. + + +// The largest rectangle is shown in the shaded area, which has area = 10 unit. + +// For example, +// Given heights = [2,1,5,6,2,3], +// return 10. + +// Hide Tags Array Stack +// Hide Similar Problems (H) Maximal Rectangle + + + +// reference: http://www.cnblogs.com/lichen782/p/leetcode_Largest_Rectangle_in_Histogram.html + +/** + * @param {number[]} heights + * @return {number} + */ +var largestRectangleArea = function(heights) { + var maxArea = 0; + + if(heights === null || heights.length === 0) { + return maxArea; + } + + var stack = []; + var i = 0; + + while(i <= heights.length) { + // Keep stack height in increasing order + // stack store the height index not the height + // everytime we encounter height smaller than the max height in the stack, we calculate area and pop + // height index in the stack until stack is empty or we found height smaller than the current height in the stack. + // taking [2,1,5,6,2,3] for example + // 2, then we encounter 1, it means anything after 1 will not yield rectangle with height greater than 1 since they all got throttle by 1 + // stack will look like + // 1. [2] + // 2. we calculate area 2*1, i is at index 0 and i is at 1 (1-0)*height(2) = 2 + // 3. [1] + // 4. [1,5] + // 5. [1,5,6] + // we calculate area 6*1, i is at index 4 and height 6 is at index 1 (4-3)*height(6) = 6 + // 6. [1,5] + // we calculate area 5*2, i is at index 4 and height 5 is at index 2 (4-2)*height(5) = 10 + // 7. [1,2] + // 8. [1,2,3] + // etc... + + if(stack.length === 0 || heights[stack[stack.length - 1]] <= heights[i]) { + stack.push(i++); + } else { + var height = heights[stack.pop()]; + var width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1; + maxArea = Math.max(height*width, maxArea); + } + } + + return maxArea; +}; \ No newline at end of file diff --git a/85 Maximal Rectangle.js b/85 Maximal Rectangle.js new file mode 100644 index 0000000..f30bce3 --- /dev/null +++ b/85 Maximal Rectangle.js @@ -0,0 +1,89 @@ +// Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing only 1's and return its area. + +// For example, given the following matrix: + +// 1 0 1 0 0 +// 1 0 1 1 1 +// 1 1 1 1 1 +// 1 0 0 1 0 +// Return 6. +// Hide Company Tags Facebook +// Hide Tags Array Hash Table Stack Dynamic Programming +// Hide Similar Problems (H) Largest Rectangle in Histogram (M) Maximal Square + + +/** + * @param {character[][]} matrix + * @return {number} + */ +var maximalRectangle = function(matrix) { + if(matrix === null || matrix.length === 0 || matrix[0].length === 0) { + return 0; + } + var heights = []; + + var maxArea = 0; + for(var x = 0; x < matrix.length; x++) { + var height = Array(matrix[0].length).fill(0); + heights.push(height); + for(var y = 0; y < matrix[0].length; y++) { + if(matrix[x][y] === '1') { + if(x === 0) { + heights[x][y] = 1; + } else { + heights[x][y] = heights[x-1][y] + 1; + } + } + } + + maxArea = Math.max(maxArea, largestRectangleArea(heights[x])); + } + + return maxArea; +}; + + +var largestRectangleArea = function(heights) { + var maxArea = 0; + + if(heights === null || heights.length === 0) { + return maxArea; + } + + var stack = []; + var i = 0; + + while(i <= heights.length) { + // Keep stack height in increasing order + // stack store the height index not the height + // everytime we encounter height smaller than the max height in the stack, we calculate area and pop + // height index in the stack until stack is empty or we found height smaller than the current height in the stack. + // taking [2,1,5,6,2,3] for example + // 2, then we encounter 1, it means anything after 1 will not yield rectangle with height greater than 1 since they all got throttle by 1 + // stack will look like + // 1. [2] + // 2. we calculate area 2*1, i is at index 0 and i is at 1 (1-0)*height(2) = 2 + // 3. [1] + // 4. [1,5] + // 5. [1,5,6] + // we calculate area 6*1, i is at index 4 and height 6 is at index 1 (4-3)*height(6) = 6 + // 6. [1,5] + // we calculate area 5*2, i is at index 4 and height 5 is at index 2 (4-2)*height(5) = 10 + // 7. [1,2] + // 8. [1,2,3] + // etc... + + if(stack.length === 0 || heights[stack[stack.length - 1]] <= heights[i]) { + stack.push(i++); + } else { + var height = heights[stack.pop()]; + var width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1; + maxArea = Math.max(height*width, maxArea); + } + } + + return maxArea; +}; + +var matrix = ["10100","10111","11111","10010"] +maximalRectangle(matrix); \ No newline at end of file diff --git a/88 Merge Sorted Array.js b/88 Merge Sorted Array.js index 35a70b2..a8aaa4a 100644 --- a/88 Merge Sorted Array.js +++ b/88 Merge Sorted Array.js @@ -16,8 +16,8 @@ var merge = function(A, m, B, n) { } } - while(n > 0){ - A[m+n-1] = B[n-1]; + while(n > 0) { + nums1[n - 1] = nums2[n - 1]; n--; } }; \ No newline at end of file diff --git a/89 Gray Code.js b/89 Gray Code.js new file mode 100644 index 0000000..ff8ac22 --- /dev/null +++ b/89 Gray Code.js @@ -0,0 +1,50 @@ + + +// The gray code is a binary numeral system where two successive values differ in only one bit. + +// Given a non-negative integer n representing the total number of bits in the code, print the sequence of gray code. A gray code sequence must begin with 0. + +// For example, given n = 2, return [0,1,3,2]. Its gray code sequence is: + +// 00 - 0 +// 01 - 1 +// 11 - 3 +// 10 - 2 +// Note: +// For a given n, a gray code sequence is not uniquely defined. + +// For example, [0,2,3,1] is also a valid gray code sequence according to the above definition. + +// For now, the judge is able to judge based on one instance of gray code sequence. Sorry about that. + + +// n = 0: 0 +// n = 1: 0, 1 +// n = 2: 00, 01, 11, 10 (0, 1, 3, 2) +// n = 3: 000, 001, 011, 010, 110, 111, 101, 100 (0, 1, 3, 2, 6, 7, 5, 4) +// 以n = 3为例,grey code中前4个包括了n = 2的所有gray code。后4个则是前4个逆序后加上2^2。 + +// 推广:n = i的grey code的前一半包括了n = i-1的所有grey code,而后一半则为前一半逆序后家上2^(i-1)。 + + +// Silly question... + +/** + * @param {number} n + * @return {number[]} + */ +var grayCode = function(n) { + if(n === 0) { + return [0]; + } + + var result = grayCode(n - 1); + var addNumber = 1 << (n - 1); + var len = result.length; + + for(var i = len; i--;) { + result.push(result[i] + addNumber); + } + + return result; +}; \ No newline at end of file diff --git a/9 Palindrome Number.js b/9 Palindrome Number.js deleted file mode 100644 index 86559ae..0000000 --- a/9 Palindrome Number.js +++ /dev/null @@ -1,37 +0,0 @@ -// Leetcode #9: -// Language: Javascript -// Problem: https://leetcode.com/problems/palindrome-number/ -// Author: Chihung Yu -/** - * Leetcode Question - * @param {number} x - * @return {boolean} - */ - -var isPalindrome = function(x) { - if(x < 0){ - return false; - } - - var div = 1; - - while(parseInt(x/div) >= 10){ - div *= 10; - } - - while(x !== 0){ - var l = parseInt(x/div); - var r = x%10; - - if(l !== r){ - return false; - } - - x = x % div; - x = parseInt(x/10); - - div = parseInt(div/100); - } - - return true; -}; \ No newline at end of file diff --git a/90 Subsets II.js b/90 Subsets II.js index 8ed90a7..cea5958 100644 --- a/90 Subsets II.js +++ b/90 Subsets II.js @@ -1,3 +1,7 @@ +// provide many different solutions +// reference: http://bangbingsyb.blogspot.com/2014/11/leetcode-subsets-i-ii.html + + /** * @param {number[]} nums * @return {number[][]} diff --git a/91 Decode Ways.js b/91 Decode Ways.js index 1a8f094..95af0a1 100644 --- a/91 Decode Ways.js +++ b/91 Decode Ways.js @@ -1,40 +1,87 @@ +// A message containing letters from A-Z is being encoded to numbers using the following mapping: + +// 'A' -> 1 +// 'B' -> 2 +// ... +// 'Z' -> 26 +// Given an encoded message containing digits, determine the total number of ways to decode it. + +// For example, +// Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). + +// The number of ways decoding "12" is 2. + /** * @param {string} s * @return {number} */ var numDecodings = function(s) { - if(s === null || s.length === 0){ + if(!s || s[0] === '0') { return 0; } + + var nums = [1, 1]; - if(s[0] === '0'){ - return 0; - } - - var nums = []; - nums[0] = 1; - nums[1] = 1; - - for(var i = 2; i <= s.length; i++){ - var tmp = parseInt(s.substring(i-1, i)); + for(var i = 2; i <= s.length; i++) { + var tmp; - if(tmp !== 0){ - nums[i] = nums[i-1]; - } else { + tmp = parseInt(s.substring(i - 1, i)); + + if(tmp === 0) { nums[i] = 0; + } else { + nums[i] = nums[i-1]; } - if(s[i - 2] !== '0'){ - tmp = parseInt(s.substring(i-2, i)); + if(s[i - 2] !== '0') { + tmp = parseInt(s.substring(i - 2, i)); - if(tmp > 0 && tmp < 27){ - nums[i] += nums[i-2]; + if(0 < tmp && tmp <= 26) { + + nums[i] += nums[i - 2]; } - } else { - nums[i] = nums[i] || 0; } } return nums[s.length]; -}; \ No newline at end of file +}; + +console.log(numDecodings('10')); + +// Using recusion +// It also store all the possible combination +// var numDecodings = function(s) { +// var result = []; + +// function traverse(s, beg, end, cur) { +// if(end > s.length) { +// return +// } + +// var str = s.substring(beg, end); +// var num = parseInt(str); + +// if(isNaN(num) || num === 0 || num > 26) { +// return; +// } + +// cur.push(str); + +// if(end === s.length){ +// result.push(cur.slice()); +// return; +// } + +// traverse(s, end, end + 1, cur); +// traverse(s, end, end + 2, cur); +// cur.pop(); +// } + +// traverse(s, 0, 1, []); +// traverse(s, 0, 2, []); + +// return result.length; +// }; + + diff --git a/92 Reverse Linked List II.js b/92 Reverse Linked List II.js index c0cc0b5..9b610bf 100644 --- a/92 Reverse Linked List II.js +++ b/92 Reverse Linked List II.js @@ -1,3 +1,5 @@ +// http://bangbingsyb.blogspot.com/2014/11/leetcode-reverse-linked-list-ii.html + /** * Definition for singly-linked list. * function ListNode(val) { @@ -12,39 +14,32 @@ * @return {ListNode} */ var reverseBetween = function(head, m, n) { - if(m === n){ + if(m >= n) { return head; } - var step = n - m; - var dummy = new ListNode(-1); + var dummy = new ListNode(0); dummy.next = head; - var pre = head = dummy; + head = dummy; - while(m > 1){ - pre = pre.next; - m--; + // move head to m - 1 node; + for(var i = 0; i < m - 1; i++) { + head = head.next; } + var pre = head.next; var cur = pre.next; - var post = cur.next; - if(step >= 1){ - while(step > 0 && post !== null){ - var temp = post.next; - post.next = cur; - cur = post; - post = temp; - step--; - } - - temp = pre.next; - pre.next = cur; - temp.next = post; + for(i = 0; i < n - m; i++) { + var tmp = cur.next; + cur.next = pre; + pre = cur; + cur = tmp; } - // safeG = head; - head = head.next; + // head.next still point to m + head.next.next = cur; + head.next = pre; - return head; + return dummy.next; }; \ No newline at end of file diff --git a/95 Unique Binary Search Trees II.js b/95 Unique Binary Search Trees II.js new file mode 100644 index 0000000..4699a9f --- /dev/null +++ b/95 Unique Binary Search Trees II.js @@ -0,0 +1,84 @@ +// Given an integer n, generate all structurally unique BST's (binary search trees) that store values 1...n. + +// For example, +// Given n = 3, your program should return all 5 unique BST's shown below. + +// 1 3 3 2 1 +// \ / / / \ \ +// 3 2 1 1 3 2 +// / / \ \ +// 2 1 2 3 +// Hide Tags Tree Dynamic Programming +// Hide Similar Problems (M) Unique Binary Search Trees (M) Different Ways to Add Parentheses + + + + + +/** +Given n, generate all structurally unique BST's (binary search trees) that store values 1...n. + +For example, +Given n = 3, your program should return all 5 unique BST's shown below. + + 1 3 3 2 1 + \ / / / \ \ + 3 2 1 1 3 2 + / / \ \ + 2 1 2 3 +confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ. +*/ +/** + * Definition for a binary tree node. + * function TreeNode(val) { + * this.val = val; + * this.left = this.right = null; + * } + */ +/** + * @param {number} n + * @return {TreeNode[]} + */ +var generateTrees = function(n) { + if (n === 0) { + return []; + } + + return genTreeHelper(1, n); +}; + +function TreeNode(val) { + this.val = val; + this.left = this.right = null; +} + +function genTreeHelper(start, end) { + var result = []; + + if (start > end) { + return [null]; + } + + + + for (var i = start; i <= end; i++) { + // let node i becomes the center node and generate it's left and right nodes + var left = genTreeHelper(start, i - 1); + var right = genTreeHelper(i + 1, end); + for (var k = 0; k < left.length; k++) { + for (var j = 0; j < right.length; j++) { + var node = new TreeNode(i); + node.left = left[k]; + node.right = right[j]; + result.push(node); + } + } + } + + return result; +} + + + + +console.log(generateTrees(2)); \ No newline at end of file diff --git a/96 Unique Binary Search Trees.js b/96 Unique Binary Search Trees.js new file mode 100644 index 0000000..2c1f537 --- /dev/null +++ b/96 Unique Binary Search Trees.js @@ -0,0 +1,49 @@ +/** + * @param {number} n + * @return {number} + */ + // https://www.youtube.com/watch?v=YDf982Lb84o +var numTrees = function(n) { + var result = [1, 1]; + + for (var i = 2; i <= n; i++) { + result[i] = 0; + for (var j = 0; j < i; j++) { + result[i] += result[j] * result[i - 1 - j]; + } + + } + return result[n]; +}; + + +// var numTrees = function(n) { +// var i, +// j, +// result = []; + +// result[0] = 1; +// result[1] = 1; + +// for (i = 2; i <= n; i++) { +// result[i] = 0; +// for (j = 0; j < i; j++) { +// result[i] += result[j] * result[i - 1 - j]; +// console.log(i, j, i - 1 - j, result) +// } + +// } +// return result[n]; +// }; + + +numTrees(4); + + +1, 2, 3, 4 + +j = r[0] +k = r[3] + +j = r[1] +k = r[2] \ No newline at end of file diff --git a/Basic Calculator II.js b/Basic Calculator II.js new file mode 100644 index 0000000..d6fa1dd --- /dev/null +++ b/Basic Calculator II.js @@ -0,0 +1,83 @@ +// Implement a basic calculator to evaluate a simple expression string. + +// The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero. + +// You may assume that the given expression is always valid. + +// Some examples: +// "3+2*2" = 7 +// " 3/2 " = 1 +// " 3+5 / 2 " = 5 +// Note: Do not use the eval built-in library function. + +// Credits: +// Special thanks to @ts for adding this problem and creating all test cases. + +// Hide Company Tags Airbnb +// Hide Tags String +// Hide Similar Problems (H) Basic Calculator (H) Expression Add Operators + + + +/** + * @param {string} s + * @return {number} + */ +var calculate = function(s) { + var values = []; + var ops = []; + + for(var i = 0; i < s.length; i++) { + var ch = s[i]; + if(ch === ' ') { + continue; + } + + if(ch.match(/\d/)) { + var num = ''; + while(i < s.length && s[i].match(/\d/)) { + num += s[i++]; + } + values.push(parseInt(num)); + i--; + } else if(ch === '-' || ch === '+' || ch === '*' || ch === '/') { + if(!hasPrecedence(ch, ops[ops.length - 1])) { + while(ops.length > 0 && !hasPrecedence(ch, ops[ops.length - 1])) { + values.push(applyOp(values.pop(), values.pop(), ops.pop())); + } + } + ops.push(ch); + } + } + + while(ops.length > 0) { + values.push(applyOp(values.pop(), values.pop(), ops.pop())); + } + + return values.pop(); +}; + +var hasPrecedence = function(op1, op2) { + var map = { + '-': 1, + '+': 1, + '/': 2, + '*': 2 + } + + return map[op1] > map[op2]; +} + +var applyOp = function(v1, v2, op) { + if(op === '*') { + return v2*v1; + } else if(op === '-') { + return v2-v1; + } else if(op === '+') { + return v2+v1; + } else if(op === '/') { + return parseInt(v2/v1); + } +} + +console.log(calculate("1+1+1*3*4/2+2*3"), eval("1+1+1*3*4/2+2*3")); \ No newline at end of file diff --git a/Basic Calculator III.js b/Basic Calculator III.js new file mode 100644 index 0000000..f145df0 --- /dev/null +++ b/Basic Calculator III.js @@ -0,0 +1,83 @@ +function evaluateStr(expression) { + var values = []; + var ops = []; + + for(var i = 0; i < expression.length; i++) { + var ch = expression[i]; + + if(ch === ' ') { + continue; + } + + if(ch.match(/\d/)) { + var numStr = ''; + + while(i < expression.length && expression[i].match(/\d/)) { + numStr += expression[i++]; + } + i--; + values.push(parseInt(numStr)); + } else if(ch === '(') { + ops.push(ch); + } else if(ch === ')') { + while(ops[ops.length - 1] !== '(') { + values.push(applyOp(values.pop(), values.pop(), ops.pop())); + } + ops.pop(); + } else if(ch === '+' || ch === '-' || ch === '*' || ch === '/') { + while(ops.length > 0 && hasPrecedence(ch, ops[ops.length - 1])) { + values.push(applyOp(values.pop(), values.pop(), ops.pop())); + } + ops.push(ch); + } + } + + while(ops.length > 0) { + values.push(applyOp(values.pop(), values.pop(), ops.pop())); + } + + return values.pop(); +} + +function hasPrecedence(op1, op2) { + var precedenceMap = { + '=': 1, + '(': 2, + '+': 3, + '-': 3, + '*': 4, + '/': 4, + '~': 4, + '^': 5 + }; + + var precendence1 = precedenceMap[op1]; + var precendence2 = precedenceMap[op2]; + + return precendence2 >= precendence1; +} + +function applyOp(val1, val2, op) { + if(op === '*') { + return val2*val1; + } else if(op === '+') { + return val2+val1; + } else if(op === '/') { + return parseInt(val2/val1); + } else if(op === '-') { + return val2-val1; + } +} + + +var data = [ + '(11+(22*3-4)*5-(3+1))', + '11+22*3+(1*3+1)', + '11+22*3-(1*3+1)', +]; + +// '11+22*3*(1*3+1)' => doesn't work + +data.forEach((d)=> { + console.log(evaluateStr(d), eval(d)); +}); diff --git a/Bean Probability.js b/Bean Probability.js new file mode 100644 index 0000000..aa54d97 --- /dev/null +++ b/Bean Probability.js @@ -0,0 +1,2 @@ +// 你有一个罐子里面有红色和白色的豆子,你每一轮拿一个豆子出来,要是白色就吃了,要是红色就放回去再拿一次,这一次无论什么颜色你都吃。。问最后吃的一个是白色的概率是多少。。 +// r/(r+w)*(r/(r+w)*f(r - 1, w)+w/(r+w)*f(r, w - 1)) \ No newline at end of file diff --git a/Can Win.js b/Can Win.js new file mode 100644 index 0000000..74e4046 --- /dev/null +++ b/Can Win.js @@ -0,0 +1,33 @@ +// CanWin. 给一个数组比如 和一个index比如4,从这个index每次可以向左或者向右跳ary的距离, 如果能跳到值为0的index则返回true。 + + +function canWin(arr) { + if(!arr || arr.length === 0) { + return false; + } + + var visitedIdx = {}; + var unvisited = []; + unvisited.push(0); + + while(unvisited.length > 0) { + var curVisitIdx = unvisited.shift(); + + if(visitedIdx[curVisitIdx] === undefined) { + visitedIdx[curVisitIdx] = true; + + if(arr[curVisitIdx] === 0) { + return true; + } + + unvisited.push(curVisitIdx + arr[curVisitIdx]); + unvisited.push(curVisitIdx - arr[curVisitIdx]); + } + } + + return false; +} + +var arr = [3,3,6,2,0,2]; +// win path 0 3 1 4 +console.log(canWin(arr)); diff --git a/Conjuct Names With Limit.js b/Conjuct Names With Limit.js new file mode 100644 index 0000000..2b96669 --- /dev/null +++ b/Conjuct Names With Limit.js @@ -0,0 +1,41 @@ +function conjuctNamesWithLimit(names, limit) { + var left, right; + + if(names.length === 0) { + return ''; + } + + if(limit === 0) { + return names.length + ' more'; + } + + if(limit >= names.length) { + left = names.slice(0, -1); + right = names.slice(-1)[0]; + return left.join(', ') + ' and ' + right; + } else { + left = names.slice(0, limit); + right = names.slice(limit); + return left.join(', ') + ' and ' + right.length + ' more'; + } +} + +var data = [ + [], + ['a','b'], + ['a','b','c'], + ['a','b','c','d'] +] + +for(var i = 0; i < 5; i++){ + data.forEach((d)=>{ + console.log(conjuctNamesWithLimit(d, i)); + }); +} + + + +console.log(conjuctNamesWithLimit(['alex', 'peter', 'jeremy'], 2) == 'alex, peter and 1 more'); +console.log(conjuctNamesWithLimit(['alex', 'peter', 'jeremy', 'joseph'], 2) == 'alex, peter and 2 more'); +console.log(conjuctNamesWithLimit(['alex', 'peter', 'jeremy', 'joseph'], 3) == 'alex, peter, jeremy and 1 more'); +console.log(conjuctNamesWithLimit(['alex', 'peter', 'jeremy', 'joseph'], 5) == 'alex, peter, jeremy and joseph'); diff --git a/Convert Binary Search Tree To Doubly Linked List.js b/Convert Binary Search Tree To Doubly Linked List.js new file mode 100644 index 0000000..0e94dad --- /dev/null +++ b/Convert Binary Search Tree To Doubly Linked List.js @@ -0,0 +1,133 @@ +// http://kubicode.me/2015/07/01/Algorithm/Binary-Search-Tree-2-Double-LinkedList/ + +// 二叉排序树的中序遍历可以得到它的排序元素,但是,但是“它不能创建任何新的节点,只能调整指针的指向”,所以,直接中序法就不可行了。 +// 大致思路是如下的: +// 如果当前根节点的左子树不为空,则 +// 递归左子树 +// 查找左子树最大的元素 +// 将该元素的right指针指向根节点,将根节点的left指针指向该元素 +// 如果当前根节点的右子树不为空,则 +// 递归右子树 +// 查找右子树最小的元素 +// 将该元素的left指针指向根节点,将根节点的right指针指向该元素 +// 注:tree的left和right结构正好对应list的pre和next结构 +// 8 +// / \ +// 3 10 +// / \ \ +// 1 6 14 +// / \ / +// 4 7 13 + +// 它依次调整的点为:1(l),4(l),7(r),4(r),7(l),13(l),13(r),10(r) +// 8 +// / \ +// 1-3 10 +// \ \ +// 6 14 +// / \ / +// 4 7 13 +// 1为3左子树的最大点,所以的右指针指向3,3的左指针指向1 + + +// 8 +// / \ +// 1-3 10 +// \ \ +// 4-6 14 +// \ / +// 7 13 + +// 4为6的左子树的最大值,所以4的右指针指向6,6左指针4 + +// 8 +// / \ +// 1-3 10 +// \ \ +// 4-6-7 14 +// / +// 13 + +// 7为6的右子树的最小值,所以7的左指针指向6,6右指针4 + +// 8 +// / \ +// 1-3 10 +// \ \ +// 4-6-7 14 +// / +// 13 + +// 4为3的右子树的最小值,所以4的左指针指向3,3右指针4 + +// 1-3-4-6-7-8 +// \ +// 10 +// \ +// 14 +// / +// 13 + +// 7为8左子树的最小值,所以7的右指针指向8,8的左指针指向7 +// 这样就完成了根节点左边的转换,右边的转换思路一致 + +/** + * 查找左子树中最大的节点 + * @param T + * @return + */ +private static TreeNode findMaxNodeInLeft(TreeNode T) +{ + TreeNode t=T.left; + if(t!=null) + while(t.right!=null) + { + t=t.right;//因为肯定右子树更加大 + } + + return t; + +} + +/** + * 查找右子树种的最小节点 + * @param T + * @return + */ +private static TreeNode findMinNodeInRight(TreeNode T) +{ + TreeNode t=T.right; + if(t!=null) + while(t.left!=null) + t=t.left; + + return t; +} + +/** + * 二叉排序树转双向链表 + * @param T + */ +public static void convertNode(TreeNode T) +{ + if(T==null) + return ; + + if(T.left!=null) + { + convertNode(T.left); + TreeNode t=findMaxNodeInLeft(T);//左子树中最大的点 它一定是在叶子上面 + t.right=T;//将左子树最小的点连在根节点的左侧 + T.left=t; + t.parent=null; + } + + if(T.right!=null) + { + convertNode(T.right); + TreeNode t=findMinNodeInRight(T); + t.left=T;//将右子树最小的点连点根节点的右侧 + T.right=t; + t.parent=null; + } +} \ No newline at end of file diff --git a/Convert Infix to Reverse Polish Notation.js b/Convert Infix to Reverse Polish Notation.js new file mode 100644 index 0000000..c4ab367 --- /dev/null +++ b/Convert Infix to Reverse Polish Notation.js @@ -0,0 +1,64 @@ +// https://www.youtube.com/watch?v=LQ-iW8jm6Mk + +function convertInfixToReversePolishNotation(strExpression) { + var precedenceMap = { + '=': 1, + '(': 2, + '+': 3, + '-': 3, + '*': 4, + '/': 4, + '~': 4, + '^': 5 + }; + + var stack = []; + var rpn = []; + + for(var i = 0; i < strExpression.length; i++) { + var ch = strExpression[i]; + if(!isNaN(parseInt(ch))) { + var num = 0; + + while(i < strExpression.length && !isNaN(parseInt(strExpression[i]))) { + num *= 10; + num += parseInt(strExpression[i]); + i++; + } + + i--; + rpn.push(num); + } else if(ch === '(') { + stack.push('('); + } else if(ch === '*' || ch === '-' || ch === '+') { + var precedence = precedenceMap[ch]; + + if(precedence > precedenceMap[stack[stack.length - 1]]) { + stack.push(ch); + } else { + while(precedenceMap[stack[stack.length - 1]] >= precedence) { + rpn.push(stack.pop()); + } + + stack.push(ch); + } + } else if(ch === ')') { + while(stack[stack.length - 1] !== '(') { + rpn.push(stack.pop()); + } + + stack.pop(); + } + } + + while(stack.length > 0) { + rpn.push(stack.pop()); + } + + return rpn; +} + + +// console.log(convertInfixToReversePolishNotation('(12*-36+(3+4-2)-(4*4+12))')); +console.log(convertInfixToReversePolishNotation('12+12*12+(3-4)')) + diff --git a/Custom Tree Problem.js b/Custom Tree Problem.js new file mode 100644 index 0000000..683116b --- /dev/null +++ b/Custom Tree Problem.js @@ -0,0 +1,119 @@ +// a ---> b +// b ---> c +// b ---> d +// a ---> e +// Print the tree that would form when each pair of these links that has the same character as start and end point is joined together. You have to maintain fidelity w.r.t. the height of nodes, i.e. nodes at height n from root should be printed at same row or column. For set of links given above, tree printed should be – + +// -->a +// |-->b +// | |-->c +// | |-->d +// |-->e +// Note that these links need not form a single tree; they could form, ahem, a forest. Consider the following links + +// a ---> b +// a ---> g +// b ---> c +// c ---> d +// d ---> e +// c ---> f +// z ---> y +// y ---> x +// x ---> w +// The output would be following forest. + +// -->a +// |-->b +// | |-->c +// | | |-->d +// | | | |-->e +// | | |-->f +// |-->g + +// -->z +// |-->y +// | |-->x +// | | |-->w + +// http://ideone.com/l0QiJx +function printTree(data) { + // 0 -> not seen, can possibly be root + // 1 -> not root + // 2 -> root + + var NOT_SEEN = 0; + var NOT_ROOT = 1; + var IS_ROOT = 2; + + var roots = Array(26).fill(NOT_SEEN); + // [[neightbors],[neighbors],...] -> idx = 0 -> 'a' + var graph = []; + for(var i = 0; i < 26; i++){ + graph.push([]); + } + + for(i = 0; i < data.length; i++) { + var pair = data[i]; + var rootChar = pair[0]; + var rootIdx = charToIdx(rootChar); + var depChar = pair[1]; + var depIdx = charToIdx(depChar); + + graph[rootIdx].push(depIdx); + + roots[depIdx] = NOT_ROOT; + + if(roots[rootIdx] === NOT_SEEN) { + roots[rootIdx] = IS_ROOT; + } + } + // console.log(roots); + for(i = 0; i < roots.length; i++) { + if(roots[i] === IS_ROOT) { + dfs(i, 0, graph); + } + } +} + +function charToIdx(char) { + var base = 'a'.charCodeAt(0); + return char.charCodeAt(0) - base; +} + +function idxToChar(idx) { + var base = 'a'.charCodeAt(0); + return String.fromCharCode(base + idx); +} + +function dfs(idx, level, graph) { + var str = ''; + + for(var i = 1; i <= level; i++) { + str += ' |'; + } + + var char = idxToChar(idx); + str += ('-->' + char); + console.log(str); + + for(i = 0; i < graph[idx].length; i++) { + var depIdx = graph[idx][i]; + dfs(depIdx, level + 1, graph); + } +} + + + +var data = [ + ['a', 'b'], + ['a', 'g'], + ['b', 'c'], + ['c', 'd'], + ['d', 'e'], + ['c', 'f'], + ['z', 'y'], + ['y', 'x'], + ['x', 'w'] +]; + +console.log(printTree(data)); \ No newline at end of file diff --git a/Data Structure Max Heap.js b/Data Structure Max Heap.js new file mode 100644 index 0000000..c8079c3 --- /dev/null +++ b/Data Structure Max Heap.js @@ -0,0 +1,148 @@ +'use strict' + +class MaxHeap { + constructor() { + this.arr = []; + } + + peek() { + return this.arr[0] || null; + } + + size() { + return this.arr.length; + } + + pollMax() { + var arr = this.arr; + var len = arr.length; + + if(len === 0) { + return null; + } + + var max = arr[0]; + arr[0] = arr[len - 1] // replace max value with the last value + + arr.pop(); + + this.sinkDown(0); + + return max; + } + + add(val) { + var arr = this.arr; + arr.push(val); + this.bubbleUp(arr.length - 1); + } + + bubbleUp(n) { + var arr = this.arr; + + while(n > 0) { + // [3,2,1] 3 as root, 2 as left child and 1 as right child + // 2 has idx = 1 and 1 has idx = 2 + // 1/2 will result in parent idx = 0 + // and 2/2 will result in parent idx = 1. So we need to add one to them and -1 at the end + var parentN = Math.floor((n + 1)/2) - 1; + + if(arr[parentN] > arr[n]) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[parentN]; + arr[parentN] = tmp; + n = parentN; + } + } + + sinkDown(n) { + var arr = this.arr; + var len = arr.length; + var val = arr[n]; + + while(true) { + + var swap = null; + var child2N = n*2 + 2; // root = 0 right child idx is (0 + 1)*2 = 2 + var child1N = n*2 + 1; // right child idx - 1 = 1 for root's left child + + if(child1N < len && arr[child1N] > val) { + swap = child1N; + } + + if(child2N < len && arr[child2N] > val && arr[child2N] >= arr[child1N]) { + swap = child2N; + } + + if(swap === null) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[swap]; + arr[swap] = tmp; + n = swap; + } + } +} + +var m = new MaxHeap(); +m.add(4); +m.add(1); +m.add(2); +m.add(1); +m.add(15); +m.add(3); +m.add(4); +m.add(3); +m.add(3); + +m.add(3); +m.add(4); +m.add(-1); + +m.add(-1); +m.add(1); +m.add(10); + +m.add(-1); +m.add(4); +m.add(8); +m.add(9); +m.add(100); +m.add(3); +m.add(7); +m.add(9); +m.add(4); + +console.log(m.arr); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); +console.log(m.pollMax()); \ No newline at end of file diff --git a/Data Structure Min Heap.js b/Data Structure Min Heap.js new file mode 100644 index 0000000..95808c8 --- /dev/null +++ b/Data Structure Min Heap.js @@ -0,0 +1,120 @@ +class MinHeap { + constructor() { + this.arr = []; + } + + peek() { + return this.arr[0] || null; + } + + size() { + return this.arr.length; + } + + pollMin() { + var arr = this.arr; + var len = arr.length; + + if(len === 0) { + return null; + } + + var min = arr[0]; + arr[0] = arr[len - 1] // swap the last value with min value + + arr.pop(); + + this.sinkDown(0); + + return min; + } + + add(val) { + var arr = this.arr; + arr.push(val); + this.bubbleUp(arr.length - 1); + } + + bubbleUp(n) { + var arr = this.arr; + + while(n > 0) { + // [1,2,3] 1 as root 2 as left child and 3 as right child + // 2 has idx = 1 and 3 has idx = 2 1/2 will result in parent idx = 0 and 2/2 will result in parent idx = 1. So we need to add one to them and -1 at the end + var parentN = Math.floor((n + 1)/2) - 1; + + if(arr[parentN] <= arr[n]) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[parentN]; + arr[parentN] = tmp; + n = parentN; + } + } + + sinkDown(n) { + var arr = this.arr; + var len = arr.length; + var val = arr[n] + + while(true) { + var swap = null; + var child2N = (n+1)*2; // root = 0 right child idx is (0 + 1)*2 = 2 + var child1N = child2N - 1; // right child idx - 1 = 1 for root's left child + if(child1N < len && arr[child1N] < val) { + swap = child1N; + } + + if(child2N < len && arr[child2N] < val && arr[child2N] <= arr[child1N]) { + swap = child2N; + } + + if(swap === null) { + break; + } + + var tmp = arr[n]; + arr[n] = arr[swap]; + arr[swap] = tmp; + n = swap; + } + } +} + + +var m = new MinHeap(); + +// m.add(4); +m.add(1); +m.add(-1); +m.add(1); +m.add(-1); +m.add(1); +m.add(-1); +m.add(-1); +m.add(1); +m.add(1); +console.log('debug', m.arr) +m.add(1); +// m.add(1); +// m.add(-1); + +// console.log(m.arr); +console.log(m.pollMin()); +console.log(m.pollMin()); +console.log(m.pollMin()); + + +console.log(m.arr); +console.log(m.pollMin()); +console.log(m.pollMin()); +console.log(m.pollMin()); +console.log(m.pollMin()); + +console.log(m.pollMin()); +console.log(m.pollMin()); +console.log(m.pollMin()); +// console.log(m.pollMin()); + diff --git a/Disambiguos Actors.js b/Disambiguos Actors.js new file mode 100644 index 0000000..b6fc508 --- /dev/null +++ b/Disambiguos Actors.js @@ -0,0 +1,73 @@ + + + +process.stdin.resume(); +process.stdin.setEncoding("ascii"); +var input = ""; +process.stdin.on("data", function (chunk) { + input += chunk; +}); +process.stdin.on("end", function () { + actorsInOrder = input.split("\n"); + disambiguated = disambiguateActors(actorsInOrder); + for(var i = 0; i < disambiguated.length; i++) { + console.log(disambiguated[i]); + } +}); + +function disambiguateActors(actorsInOrder) { + // WRITE YOUR CODE HERE + var hash = {}; + + for(var i = 0; i < actorsInOrder.length; i++){ + var actor = actorsInOrder[i]; + if(hash[actor] !== undefined){ + hash[actor] += 1; + } else { + hash[actor] = 1; + } + } + + for(var i = actorsInOrder.length; i--;){ + actor = actorsInOrder[i]; + if(hash[actor] !== 1) { + var count = hash[actor] === -1 ? 1 : hash[actor]; + actorsInOrder[i] = postfixActorName(actor, count); + hash[actor] -= 1; + + if(hash[actor] === 1) { + hash[actor] = -1; + } + } + } + + for(var i = 0; i < actorsInOrder.length; i++){ + console.log(actorsInOrder[i]) + } + +} + +function postfixActorName(actorName, num) { + return actorName + " (" + convertNumberToRomanLetter(num) + ")"; +} + +function convertNumberToRomanLetter(num) { + var dict = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"]; + var val = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1]; + var result = ""; + + for(var i = 0; i < val.length; i++) { + var v = val[i]; + + if(num >= v) { + var count = parseInt(num/v); + num %= v; + + for(var j = 0; j < count; j++) { + result = result + dict[i]; + } + } + } + + return result; +} \ No newline at end of file diff --git a/Find Duplicate Files.js b/Find Duplicate Files.js new file mode 100644 index 0000000..e6736cc --- /dev/null +++ b/Find Duplicate Files.js @@ -0,0 +1,24 @@ +// 题目是给定两个函数, get_files(dir), get_dir(dir) 返回所有内容相同的file, +// 问怎么定义内容相同, 然后用hashing把文件的内容hash成key放在dictionary,最后返回这个dictionary。很快写完code,test case。 小哥follow up说, 如果hashing非常expensive怎么办, 答曰hashing前先check file size,如果文件大小一样,再用hashing判断是不是一样。 小哥点头,又来一个follow up说get_files, get_dir如果expensive怎么办,答曰用parrallel programming (gpu or multi core) 可以优化,小哥点头。迎来第五轮system design的面试官。 + +// getDir(dir) +// getFiles(dir) + + +function findDuplicateFiles(dir) { + var files = []; + var queue = []; + + queue.push(dir); + + // get all files + while(queue.length > 0) { + var curDir = queue.shift(); + + var curFiles = getFiles(curDir); + var curDirs = getDir(curDir); + + queue.concat(curDirs); + files.concat(curFiles); + } +} \ No newline at end of file diff --git a/Find Median in K Sorted Arrays.js b/Find Median in K Sorted Arrays.js new file mode 100644 index 0000000..3f6973d --- /dev/null +++ b/Find Median in K Sorted Arrays.js @@ -0,0 +1,147 @@ +var data = [ + [1,2,3,4,5,6,7,19], + [2,3,5,7,8,10,11], + [2,3,5,7,8,9], + [10,13,15,17,18,100], + [5,8,100,1002,1033,1044] +]; + +findMedianInKSortedArrays(data); + +function findMedianInKSortedArrays(arrs) { + var len = 0; + + for(var i = 0; i < arrs.length; i++) { + len += arrs[i].length; + } + + var kth = Math.floor(len/arrs.length); + var list = []; + + +} + + +function findMedianInKArrs(arrs) { + var len = 0; + for(var i = 0; i < arrs.length; i++) { + len = arrs[i].length; + } + + findKthInKArrs(arrs, len); +} + + +function findKthInKArrs(arrs, n) { + var min = Infinity; + var max = -Infinity; + + for(var i = 0; i < arrs.length; i++) { + min = Math.min(arrs[i][0], min); + max = Math.max(arrs[i][arrs[i].length - 1], max); + } + + var removed = 0; + var dividers = []; + + for(var i = 0; i < arrs.length; i++) { + + } +} + + + + + +function findKth(a, m, b, n, k) { + // always assume that m is equal or smaller than n + if(m > n) { + return findKth(b, n, a, m, k); + } + + if(m === 0) { + return b[k-1]; + } + + if(k === 1) { + return Math.min(a[0],b[0]); + } + + // divide k into two parts + var pa = Math.min(parseInt(k/2), m); + var pb = k - pa; + + if(a[pa - 1] < b[pb - 1]) { + return findKth(a.slice(pa), m - pa, b, n, k - pa); + } else if(a[pa - 1] > b[pb - 1]) { + return findKth(a, m, b.slice(pb), n - pb, k - pb); + } else { + return a[pa - 1]; + } +} + + + + + + + + + + + + + +// function findMedian(arrs) { +// var n = 0; +// var min, max; + +// for(var i = 0; i < arrs.length; i++) { +// n += arrs[i].length; +// } + +// var res = mergeKLists(arrs, 0, arrs.length - 1); + +// function mergeKLists(arrs, left, right) { +// if(left === right) { +// return arrs[left]; +// } + +// if(left > right) { +// return []; +// } + +// var mid = Math.floor((left + right)/2); + +// var arr1 = mergeKLists(arrs, left, mid); +// var arr2 = mergeKLists(arrs, mid + 1, right); + +// return merge2Lists(arr1, arr2); +// } + +// function merge2Lists(arr1, arr2) { +// var res = []; +// var i = 0; +// var j = 0; +// while(i < arr1.length && j < arr2.length) { +// if(arr1[i] < arr2[j]) { +// res.push(arr1[i++]); +// } else { +// res.push(arr2[j++]); +// } +// } + +// while(i < arr1.length) { +// res.push(arr1[i++]); +// } +// while(j < arr2.length) { +// res.push(arr2[j++]); +// } + +// return res; +// } + +// return res; +// } + +// console.log(findMedian(data)); \ No newline at end of file diff --git a/Javascript Closure Questions.js b/Javascript Closure Questions.js new file mode 100644 index 0000000..22e445a --- /dev/null +++ b/Javascript Closure Questions.js @@ -0,0 +1,24 @@ +// implement function add in such a way that: +// add() => 0 +// add(1)(2)() => 3 +// add(n0)(n1)...(nk)() => n0+n1+...+nk + +function add(val){ + var total = 0; + var result; + var step = function(val){ + if(val === undefined){ + result = total; + total = 0; + return result; + } else { + total += val; + } + + return step; + } + + result = step(val); + + return result; +} \ No newline at end of file diff --git a/Job Sequencing Problem.js b/Job Sequencing Problem.js new file mode 100644 index 0000000..8dd9f71 --- /dev/null +++ b/Job Sequencing Problem.js @@ -0,0 +1,103 @@ +// Given an array of jobs where every job has a deadline and associated profit if the job is finished before the deadline. It is also given that every job takes single unit of time, so the minimum possible deadline for any job is 1. How to maximize total profit if only one job can be scheduled at a time. + +// Examples: + +// Input: Four Jobs with following deadlines and profits +// JobID Deadline Profit +// a 4 20 +// b 1 10 +// c 1 40 +// d 1 30 +// Output: Following is maximum profit sequence of jobs +// c, a + + +// Input: Five Jobs with following deadlines and profits +// JobID Deadline Profit +// a 2 100 +// b 1 19 +// c 2 27 +// d 1 25 +// e 3 15 +// Output: Following is maximum profit sequence of jobs +// c, a, e +// We strongly recommend to minimize your browser and try this yourself first. + +// A Simple Solution is to generate all subsets of given set of jobs and check individual subset for feasibility of jobs in that subset. Keep track of maximum profit among all feasible subsets. The time complexity of this solution is exponential. + +// This is a standard Greedy Algorithm problem. Following is algorithm. + +// 1) Sort all jobs in decreasing order of profit. // 4, 2, 1, 6, 2 becomes 6, 4, 2, 2, 1 +// 2) Initialize the result sequence as first job in sorted jobs. +// 3) Do following for remaining n-1 jobs +// .......a) If the current job can fit in the current result sequence +// without missing the deadline, add current job to the result. +// Else ignore the current job. +// The Following is C++ implementation of above algorithm. + +// Program to find the maximum profit job sequence from a given array +// of jobs with deadlines and profits +#include +#include +using namespace std; + +// A structure to represent a job +struct Job +{ + char id; // Job Id + int dead; // Deadline of job + int profit; // Profit if job is over before or on deadline +}; + +// This function is used for sorting all jobs according to profit +bool comparison(Job a, Job b) +{ + return (a.profit > b.profit); +} + +// Returns minimum number of platforms reqquired +void printJobScheduling(Job arr[], int n) +{ + // Sort all jobs according to decreasing order of prfit + sort(arr, arr+n, comparison); + + int result[n]; // To store result (Sequence of jobs) + bool slot[n]; // To keep track of free time slots + + // Initialize all slots to be free + for (int i=0; i=0; j--) + { + // Free slot found + if (slot[j]==false) + { + result[j] = i; // Add this job to result + slot[j] = true; // Make this slot occupied + break; + } + } + } + + // Print the result + for (int i=0; i 360 +// [0,...,359] +// { time: timestamp, count: integer} +// lastTime: 1, count +// 丟掉盒子 + +class Node { + constructor(time) { + this.time = time; + this.count = 0; + this.next = null; + } +} + +class Logger { + constructor(precision, seconds) { + this.lastTimeHit = null; + this.precision = precision; // 1 src + this.seconds = seconds; // 360 seconds + // this.count = []; // initialize later // linklist structure + + this.head = this.tail = new Node(this.getCurTimeInSec()); + this.count = 0; + this.totalCount = 0; + } + + logHit() { // assume this log hit got hits more + var curTimeInSec = this.getCurTimeInSec(); + + if(curTimeInSec === this.lastTimeHit) { + this.tail.count++; + } else { + var node = new Node(curTimeInSec); + node.count+=; + this.tail.next = node; + this.tail = node; + this.count++; + } + + // 361 > 360 + if(this.count > this.seconds) { + var next = this.head.next; + this.head.next = null; + this.head = next; + this.totalCount -= this.head.count; + } + + this.totalCount++; + + } + + getHits() { + var curTime = this.getCurTimeInSec(); + var startTime = curTime - this.seconds; // 360 seconds + var discount = 0; + + while(this.head && this.head.time < startTime) { + discount += this.head.count; + var next = this.head.next; + this.head.next = null; + this.head = next; + } + + if(this.head === null) { + this.head = this.tail = new Node(curTime); + } + + this.totalCount -= discount; + + return this.totalCount; + } + + getCurTimeInSec() { + var curTime = Date.now(); // assuming this is ms + var curTimeInSec = Math.floor(curTime / 1000); + return curTimeInSec; + } +} + + +new Logger(1, 6); +// starting 123 +// loghit 154 + +// head(123) -> node(154) +// tail at node(154) +//loghit 160 + +// head(123) -> node(154) -> node(160); +// tail at 160 +// getHits() // curTime 510 +// 510 - 360 = 150 + +// logHit at 100 +// totalCount -> 1 +// head(0) -> node(100) +// tail is at node(100) +// getHits at 500 +// 500 - 360 = 140 +// dicount += 0 +// dicount += 1 +// curHead === null diff --git a/Longest Common Subsequence.js b/Longest Common Subsequence.js new file mode 100644 index 0000000..0717f81 --- /dev/null +++ b/Longest Common Subsequence.js @@ -0,0 +1,27 @@ +// https://www.youtube.com/watch?v=NnD96abizww + + +function longestCommonSubsequence(str1, str2) { + var dp = []; + + for(var i = 0 ; i <= str1.length; i++) { + dp.push([]); + for(var j = 0; j <= str2.length; j++) { + dp[i].push(0); + } + } + + var result = []; + + for(i = 1 ; i <= str1.length; i++) { + for(j = 1; j <= str2.length; j++) { + if(str1[i-1] === str2[j-1]) { + dp[i][j] = dp[i-1][j-1] + 1; + } else { + dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]); + } + } + } + + return dp[str1.length][str2.length]; +} \ No newline at end of file diff --git a/Matrix Diagonal Traversal.js b/Matrix Diagonal Traversal.js new file mode 100644 index 0000000..ee55f6e --- /dev/null +++ b/Matrix Diagonal Traversal.js @@ -0,0 +1,82 @@ +// Print a N x M matrix in diagonal from the upper left to lower right. +// However, with the following caveat. +// It's easy to just show the input and expect output. +// matrix: [ +// 'abc', +// 'defg', +// 'hijk' +// ] +// output: aej bfk cg di h + + +// matrix: [ +// 'abc', +// 'defgsb', +// 'hijk' +// ] +// output: aej bfk cg s b di h + +function matrixDiagonalTraversal(matrix) { + var maxLen = 0; + for(var i = 0; i < matrix.length; i++) { + maxLen = Math.max(matrix[i].length, maxLen); + } + + for(i = 0; i < matrix.length; i++) { + var row = matrix[i]; + var cnt = maxLen - row.length; + + while(cnt > 0) { + matrix[i] += ' '; + cnt--; + } + + var leftStr = matrix[i].substring(i); + + var reversedRightStr = ''; + cnt = i; + + while(cnt > 0) { + reversedRightStr += matrix[i][--cnt]; + } + + matrix[i] = leftStr + reversedRightStr; + } + + var result = ''; + + for(i = 0; i < maxLen; i++) { + for(var j = 0; j < matrix.length; j++) { + if(matrix[j][i] !== ' ') { + result += matrix[j][i]; + } + } + } + + return result; +} + + + + +console.log(matrixDiagonalTraversal([ + 'abc', + 'defgsb', + 'hijk', + 'lm', + 'nopq' +])); + + +'abc___' +'deggsb' +'hijk__' +'lm____' +'nopq__' + + +'abc___' +'efgsbd' +'jk__ih' +'____ml' +'__qpon' \ No newline at end of file diff --git a/Maximum Sum Rectangular Submatrix in Matrix Dynamic Programming:2D.js b/Maximum Sum Rectangular Submatrix in Matrix Dynamic Programming:2D.js new file mode 100644 index 0000000..1df4f58 --- /dev/null +++ b/Maximum Sum Rectangular Submatrix in Matrix Dynamic Programming:2D.js @@ -0,0 +1,86 @@ +/** + * @param {number[]} nums + * @return {number} + */ + + // Kadane's algo +function maxSubArray(nums) { + var max = -Infinity; + var curMax = 0; + var beg = 0; + var end = 0; + + for(var i = 0; i < nums.length; i++) { + var val = nums[i]; + + curMax += val; + + if(curMax > max) { + end = i; + max = curMax; + } + + if(curMax < 0) { + beg = i + 1; + curMax = 0; + } + } + + return { + max: max, + beg: beg, + end: end + }; +}; + + +// https://www.youtube.com/watch?v=yCQN096CwWM + +var sampleData = [ + [ 2, 1,-3,-4, 5], + [ 0, 6, 3, 4, 1], + [ 2,-2,-1, 4,-5], + [-3, 3, 1, 0, 3] +] + +// move from left to right +function maximumRectangularSubmatrix(matrix) { + var row = matrix.length; + var col = matrix[0].length; + var max = -Infinity; + var maxTop = 0; + var maxLeft = 0; + var maxRight = 0; + var maxBottom = 0; + + for(var left = 0; left < col; left++){ + var subArray = []; + + for(var right = left; right < col; right++){ + for(var i = 0; i < row; i++) { + subArray[i] = subArray[i] || 0; + subArray[i] += matrix[i][right]; + } + + var info = maxSubArray(subArray); + + if(info.max > max) { + max = info.max; + maxLeft = left; + maxRight = right; + maxTop = info.beg; + maxBottom = info.end; + } + } + } + + return { + max: max, + left: maxLeft, + right: maxRight, + top: maxTop, + bottom: maxBottom + } +} + +console.log(maximumRectangularSubmatrix(sampleData)); \ No newline at end of file diff --git a/Merge Two Lists Into Sorted List.js b/Merge Two Lists Into Sorted List.js new file mode 100644 index 0000000..f761047 --- /dev/null +++ b/Merge Two Lists Into Sorted List.js @@ -0,0 +1,82 @@ +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} head + * @return {ListNode} + */ + +// !!! we can concat two list together than use merge sort to sort the merged list + +var sortList = function(head) { + if(head === null) { + return null; + } + + var len = 0; + var p = head; + + while(p) { + len++; + p = p.next; + } + + var newHead = sort(len); + + return newHead; + + function sort(len) { + // there will be no case of len = 0 which is caused by 1/2 + if(len === 1) { + var temp = head; + // !!! important: moving pointer to the next + // e.g. 1->2->3->4 + // head-> 1 + // now head will be point to 2 + head = head.next; + temp.next = null; + return temp; + } + // there will be no case of len = 0 which is caused by 1/2 + var leftHead = sort(parseInt(len/2)); + var rightHead = sort(len - parseInt(len/2)); + var newHead = merge(leftHead, rightHead); + + return newHead; + } + + function merge(first, second) { + var h = new ListNode(-1); + var cur = h; + + while(first && second) { + + + if(first.val <= second.val) { + cur.next = first; + first = first.next; + } else { + cur.next = second; + second = second.next; + } + + cur = cur.next; + } + + if(first) { + cur.next = first; + } + + if(second) { + cur.next = second; + } + + cur = h.next; + h.next = null; + return cur; + } +}; \ No newline at end of file diff --git a/Min CPU Count.js b/Min CPU Count.js new file mode 100644 index 0000000..9869342 --- /dev/null +++ b/Min CPU Count.js @@ -0,0 +1,23 @@ +// 一个list of task, task纪录了开始时间,结束时间,需要的cpu 数量。 求最小的cpu数量可以满足complete all task without cpu deficit + +var minCPU = function(intervals) { + var schedule = {}; + + intervals.forEach((interval)=>{ + schedule[interval.start] = schedule[interval.start] || 0; + schedule[interval.start] += interval.cpu; + + schedule[interval.end] = schedule[interval.end] || 0; + schedule[interval.start] -= interval.cpu; + }); + + var maxCpu = 0; + var curCpu = 0; + + for(var i in schedule) { + curCpu += schedule[i]; + maxCpu = Math.max(maxCpu, curCpu); + } + + return maxCpu; +}; \ No newline at end of file diff --git a/Parse HTML.js b/Parse HTML.js new file mode 100644 index 0000000..8c11db8 --- /dev/null +++ b/Parse HTML.js @@ -0,0 +1,70 @@ +// Hulu + + +function parseHtml(htmlArr) { + var context = []; + var stack = []; + + for(var i = 0; i < htmlArr.length; i++){ + var htmlTag = htmlArr[i]; + + if(htmlTag[0] === '/'){ + context = stack.pop(); + } else { + var map = {}; + map[htmlTag] = []; + context.push(map); + stack.push(context); + context = map[htmlTag]; + } + } + + return context; +} + + + + +var htmlArr = [ + 'html', + 'body', + 'div', + 'a', + '/a', + '/div', + 'div', + 'a', + '/a', + '/div', + 'div', + 'a', + '/a', + '/div', + '/body', + '/html' +]; + + +console.log(parseHtml(htmlArr)); +// will generate + +/* +[{ + html: [{ + body: [{ + div: [{ + a: [{}] + }] + },{ + div: [{ + a: [{}] + }] + },{ + div: [{ + a: [{}] + }] + }] + }] +}] +*/ + diff --git a/Parse Log Top k Longest Running Job.js b/Parse Log Top k Longest Running Job.js new file mode 100644 index 0000000..e69de29 diff --git a/Parse String Into Array.js b/Parse String Into Array.js new file mode 100644 index 0000000..9af8761 --- /dev/null +++ b/Parse String Into Array.js @@ -0,0 +1,79 @@ +// Given a string, parse it and return a string array. +// It's like a tokenizer, but the rules are too... +// For exmple, string="abc(edf)hij{klmn}opq[rst]uvw" +// Rule 1: +// The delimitors are (), {}, []. They are in pair. +// So output array: ["abc", "edf", "hij", "klmn", "opq", "rst", "uvw"] +// Rule 2: +// if any two consecutive "(" means escaping, that is "((" is actually output char "(". +// It's not part of the delimitor. Similar to ")", "{", "}", "[", "]". abc(e))df) => ["abc", "e)df"], since the "))" outpus ")". +// Rule 3: if "{" is inside a delimitor pair (), then "{" isn't part of the delimitor. Output it as is. abc(e{df}}g) => ["abc", "e{df}}g"] +// So, parse the given string and assume the given string is always valid and parsable. + + + +function tokenizeString(str) { + var result = []; + var cur = ''; + var i = 0; + + while(i < str.length){ + var c = str[i]; + + // Need to take care of [ && [[ && [[[ + // [123] -> ['123'], [[123]] --> ['[123]'], [[[123]]] -> ['[[123]]'] + if(c === '[' || c === '(' || c === '{') { + if(cur !== '') { + result.push(cur); + cur = ''; + } + var eq = escapeQuote(str, i + 1, c); + result.push(eq[0]); + i = eq[1]; + + } else { + cur += c; + i++; + } + } + + if(cur !== '') { + result.push(cur); + } + + return result; + + function escapeQuote(str, i, quoteSym) { + var quoteCnt = 1; + var result = ''; + + while(i < str.length) { + var c = str[i] + if(quoteSym === c) { + quoteCnt++; + } else if((quoteSym === '[' && c === ']') + || (quoteSym === '{' && c === '}') + || (quoteSym === '(' && c === ')') + ) { + quoteCnt--; + } + + i++; + + if(quoteCnt === 0) { + break; + } + + result += c; + } + + return [result, i]; + } +} + + +var str = "abc(((edf)))hij{{klmn}}opq[rst]uvw"; +// answer should be ['abc', '((edf))', 'hij', '{klmn}', 'opq', 'rst', 'uvw'] + +console.log(tokenizeString(str)); +// [ 'abc', '((edf))', 'hij', '{klmn}', 'opq', 'rst', 'uvw' ] diff --git a/README.md b/README.md index 0be90c0..a7347ec 100644 --- a/README.md +++ b/README.md @@ -1,142 +1,278 @@ -# leetcode-javascript -Leetcode Solutions using Javascript -By Chihung Yu -
-1 Two Sum.js
-100 Same Tree.js
-101 Symmetric Tree.js
-102 Binary Tree Level Order Traversal.js
-103 Binary Tree Zigzag Level Order Traversal.js
-104 Maximum Depth of Binary Tree.js
-105 Construct Binary Tree from Preorder and Inorder Traversal.js
-106 Construct Binary Tree from Inorder and Postorder Traversal.js
-107 Binary Tree Level Order Traversal II.js
-108 Convert Sorted Array to Binary Search Tree.js
-11 Container With Most Water.js
-110 Balanced Binary Tree.js
-111 Minimum Depth of Binary Tree.js
-112 Path Sum.js
-114 Flatten Binary Tree to Linked List.js
-116 Populating Next Right Pointers in Each Node.js
-118 Pascal's Triangle.js
-119 Pascal's Triangle II.js
-12 Integer to Roman.js
-120 Triangle.js
-121 Best Time to Buy and Sell Stock.js
-122 Best Time to Buy and Sell Stock II.js
-127 Word Ladder II.js
-129 Sum Root to Leaf Numbers.js
-13 Roman to Integer.js
-131 Palindrome Partitioning.js
-136 Single Number.js
-137 Single Number II.js
-139 Word Break.js
-14 Longest Common Prefix.js
-141 Linked List Cycle.js
-144 Binary Tree Preorder Traversal My Submissions Question.js
-15 3Sum.js
-150 Evaluate Reverse Polish Notation.js
-151 Reverse Words in a String.js
-152 Maximum Product Subarray.js
-153 Find Minimum in Rotated Sorted Array.js
-155 Min Stack.js
-16 3Sum Closest.js
-160 Intersection Of Two Linked Lists.js
-162 Find Peak Element.js
-165 Compare Version Numbers.js
-166 Fraction to Recurring Decimal.js
-168 Excel Sheet Column Title.js
-169 Majority Element.js
-17 Letter Combinations of a Phone Number.js
-171 Excel Sheet Column Number.js
-172 Factorial Trailing Zeroes.js
-173 Binary Search Tree Iterator.js
-179 Largest Number.js
-189 Rotate Array.js
-19 Remove Nth Node From End of List.js
-190 Reverse Bits.js
-191 Number of 1 Bits.js
-198 House Robber.js
-199 Binary Tree Right Side View.js
-2 Add Two Numbers.js
-20 Valid Parentheses.js
-200 Number of Islands.js
-201 Bitwise AND of Numbers Range.js
-202 Happy Number.js
-203 Remove Linked List Elements.js
-204 Count Primes.js
-205 Isomorphic Strings.js
-206 Reverse Linked List.js
-207 Course Schedule.js
-209 Minimum Size Subarray Sum.js
-21 Merge Two Sorted Lists.js
-211 Add and Search Word - Data structure design.js
-217 Contain Duplicate.js
-219 Contains Duplicate II.js
-22 Generate Parentheses.js
-223 Rectangle Area.js
-225 Implement Stack Using Queues.js
-226 Invert Binary Tree.js
-228 Summary Ranges.js
-229 Majority Element II.js
-231 Power of Two.js
-232 Implement Queue using Stacks.js
-234 Palindrome Linked List.js
-235 Lowest Common Ancestor Of a Binary Search Tree.js
-237 Delete Node in a Linked List.js
-24 Swap nodes in Pairs.js
-240 Search a 2D Matrix II.js
-241 Different Ways to Add Parentheses.js
-242 Valid Anagram.js
-26 Remove Duplicates from Sorted Array.js
-268 Missing Number.js
-27 Remove Element.js
-28 Implement strStr().js
-3 Longest Substring Without Repeating Characters.js
-31 Next Permutation.js
-318 Maximum Product of Word Lengths My Submissions Question.js
-34 Search for a Range.js
-35 Search Insert Position.js
-36 Valid Sudoku.js
-38 Count and Say.js
-39 Combination Sum.js
-40 combination Sum II.js
-43 Multiply Strings.js
-46 Permutations.js
-48 Rotate Image.js
-49 Anagrams.js
-49 Group Anagrams.js
-5 Longest Palindromic Substring.js
-50 Pow(x, n).js
-51 N-Queens.js
-53 Maximum Subarray.js
-54 Spiral Matrix.js
-55 Jump Game.js
-58 Length of Last Word.js
-59 Spiral Matrix II.js
-61 Rotate List.js
-62 Unique Paths.js
-63 Unique Paths II.js
-64 Minimum Path Sum.js
-66 Plus One.js
-67 Add Binary.js
-70 Climbing Stairs.js
-71 Simplify Path.js
-72 Edit Distance.js
-74 Search a 2D Matrix.js
-75 Sort Colors.js
-77 Combinations.js
-8 String to Integer (atoi).js
-80 Remove Duplicates from Sorted Array II.js
-81 Search in Rotated Sorted Array II.js
-82 Remove Duplicates from Sorted List II.js
-83 Remove Duplicates from Sorted List.js
-86 Partition List.js
-88 Merge Sorted Array.js
-9 Palindrome Number.js
-90 Subsets II.js
-91 Decode Ways.js
-92 Reverse Linked List II.js
-93 Restore IP Addresses.js
-94 Binary Tree Inorder Traversal.js
-98 Validate Binary Search Tree.js
\ No newline at end of file +# Leetcode Problems and interview problems in Javascript +- +- 10 Regular Expresion Matching.js +- 100 Same Tree.js +- 101 Symmetric Tree.js +- 102 Binary Tree Level Order Traversal.js +- 103 Binary Tree Zigzag Level Order Traversal.js +- 104 Maximum Depth of Binary Tree.js +- 105 Construct Binary Tree from Preorder and Inorder Traversal.js +- 106 Construct Binary Tree from Inorder and Postorder Traversal.js +- 107 Binary Tree Level Order Traversal II.js +- 108 Convert Sorted Array to Binary Search Tree.js +- 11 Container With Most Water.js +- 110 Balanced Binary Tree.js +- 111 Minimum Depth of Binary Tree.js +- 112 Path Sum.js +- 114 Flatten Binary Tree to Linked List.js +- 116 Populating Next Right Pointers in Each Node.js +- 117 Populating Next Right Pointer.js +- 117 Populating Next Right Pointers in Each Node II.js +- 118 Pascal's Triangle.js +- 119 Pascal's Triangle II.js +- 12 Integer to Roman.js +- 120 Triangle.js +- 121 Best Time to Buy and Sell Stock.js +- 122 Best Time to Buy and Sell Stock II.js +- 123 Best Time to Buy and Sell Stock III.js +- 124 Binary Tree Maximum Path Sum.js +- 125 Valid Palindrome.js +- 126 Word Ladder II.js +- 127 Word Ladder.js +- 129 Sum Root to Leaf Numbers.js +- 13 Roman to Integer.js +- 131 Palindrome Partitioning.js +- 133 Clone Graph.js +- 136 Single Number.js +- 137 Single Number II.js +- 138 Copy List With Random Pointer.js +- 139 Word Break.js +- 14 Longest Common Prefix.js +- 140 Word Break II.js +- 141 Linked List Cycle.js +- 144 Binary Tree Preorder Traversal My Submissions Question.js +- 145 Binary Tree Post Order Traversal.js +- 146 LRU Cache.js +- 148 Sort List.js +- 149 Max Points on a Line.js +- 15 3Sum.js +- 150 Evaluate Reverse Polish Notation.js +- 151 Reverse Words in a String.js +- 152 Maximum Product Subarray.js +- 153 Find Minimum in Rotated Sorted Array.js +- 155 Min Stack.js +- 156 Binary Tree Upside Down.js +- 159 Longest Substring with At Most Two Disctinct Characters.js +- 16 3Sum Closest.js +- 160 Intersection Of Two Linked Lists.js +- 161 One Edit Distance.js +- 162 Find Peak Element.js +- 165 Compare Version Numbers.js +- 166 Fraction to Recurring Decimal.js +- 168 Excel Sheet Column Title.js +- 169 Majority Element.js +- 17 Letter Combinations of a Phone Number.js +- 170 Two Sum III - Data structure design.js +- 171 Excel Sheet Column Number.js +- 172 Factorial Trailing Zeroes.js +- 173 Binary Search Tree Iterator.js +- 179 Largest Number.js +- 186 Reverse Words in a String II.js +- 187 Repeated DNA Sequences.js +- 188 Best Time to Buy and Sell Stock IV.js +- 189 Rotate Array.js +- 19 Remove Nth Node From End of List.js +- 190 Reverse Bits.js +- 191 Number of 1 Bits.js +- 198 House Robber.js +- 199 Binary Tree Right Side View.js +- 2 Add Two Numbers.js +- 20 Valid Parentheses.js +- 200 Number of Islands.js +- 201 Bitwise AND of Numbers Range.js +- 202 Happy Number.js +- 203 Remove Linked List Elements.js +- 204 Count Primes.js +- 205 Isomorphic Strings.js +- 206 Reverse Linked List.js +- 207 Course Schedule.js +- 208 Implement Trie (Prefix Tree).js +- 209 Minimum Size Subarray Sum.js +- 21 Merge Two Sorted Lists.js +- 210 Course Schedule II.js +- 211 Add and Search Word - Data structure design.js +- 212 Word Search II.js +- 213 House Robber II.js +- 215 Kth Largest Element in an Array.js +- 215 Kth Largest Element in an Array.py +- 217 Contain Duplicate.js +- 219 Contains Duplicate II.js +- 22 Generate Parentheses.js +- 220 Contains Duplicate III.js +- 221 Maximal Square.js +- 222. Count Complete Tree Nodes.js +- 223 Rectangle Area.js +- 224 Basic Calculator.js +- 225 Implement Stack Using Queues.js +- 226 Invert Binary Tree.js +- 228 Summary Ranges.js +- 229 Majority Element II.js +- 23 Merge k Sorted Lists.js +- 231 Power of Two.js +- 232 Implement Queue using Stacks.js +- 233 Number of Digit One.js +- 234 Palindrome Linked List.js +- 235 Lowest Common Ancestor Of a Binary Search Tree.js +- 236 Lowest Common Ancestor of a Binary Tree.js +- 237 Delete Node in a Linked List.js +- 238 Product of Array Except Self.js +- 239 Sliding Window Maximum.js +- 24 Swap nodes in Pairs.js +- 240 Search a 2D Matrix II.js +- 241 Different Ways to Add Parentheses.js +- 242 Valid Anagram.js +- 243 Shortest Word Distance.js +- 244 Shortest Word Distance II.js +- 245 Shortest Word Distance III.js +- 249 Group Shifted Strings.js +- 25 Reverse Nodes in k-Group.js +- 252 Meeting Rooms.js +- 253 Meeting Rooms II.js +- 254 Factor Combinations.js +- 256 Paint House.js +- 257 Binary Tree Paths.js +- 26 Remove Duplicates from Sorted Array.js +- 261 Graph Valid Tree.js +- 263 Ugly Number.js +- 264 Ugly Number II.js +- 265 Paint House II.js +- 266 Palindrome Permutation.js +- 268 Missing Number.js +- 269 Alien Dictionary.js +- 27 Remove Element.js +- 277 Find the Celebrity.js +- 278 First Bad Version.js +- 279. Perfect Squares.js +- 28 Implement strStr().js +- 283 Move Zeroes.js +- 285 Inorder Successor in BST.js +- 286 Walls and Gates.js +- 289. Game of Life.js +- 293 Flip Game.js +- 294 Flip Game II.js +- 295 Find Median From Data Stream.js +- 296 Best Meeting Point.js +- 297 Serialize and Deserialize Binary Tree My Submissions Question.js +- 3 Longest Substring Without Repeating Characters.js +- 300 Longest Increasing Subsequence.js +- 301 Remove Invalid Parentheses.js +- 307 Range Sum Query - Mutable.js +- 31 Next Permutation.js +- 314 Binary Tree Vertical Order Traversal.js +- 317 Shortest Distance From All Buildings.js +- 318 Maximum Product of Word Lengths My Submissions Question.js +- 320 Generalized Abbreviation.js +- 322 Coin Change.js +- 33 Search in Rotated Sorted Array.js +- 334 Increasing Triplet Subsequence.js +- 335 Self Crossing.js +- 337 House Robber III.js +- 338 Count Bits.js +- 339 Nested List Weight Sum.js +- 34 Search for a Range.js +- 340 Longest Substring With At Most K Distinct Characters.js +- 341 Flatten Nested List Iterator.js +- 348. Design Tic-Tac-Toe.java +- 349 Intersection of Two Arrays.js +- 35 Search Insert Position.js +- 350 Intersection of Two Arrays II.js +- 353 Design Snake Game.js +- 36 Valid Sudoku.js +- 364 Nested List Weight Sum II.js +- 366 Find Leaves of Binary Tree.js +- 367 Valid Perfect Square.js +- 37 Sudoku Solver.js +- 371 Sum of Two Integers.js +- 38 Count and Say.js +- 39 Combination Sum.js +- 4. Median of Two Sorted Arrays.js +- 40 combination Sum II.js +- 42 Trapping Rain Water.js +- 43 Multiply Strings.js +- 45 Jump Game II.js +- 46 Permutations.js +- 47 Permutations II.js +- 48 Rotate Image.js +- 49 Anagrams.js +- 49 Group Anagrams.js +- 5 Longest Palindromic Substring.js +- 50 Pow(x, n).js +- 51 N-Queens.js +- 53 Maximum Subarray.js +- 54 Spiral Matrix.js +- 55 Jump Game.js +- 56. Merge Intervals.js +- 57. Insert Interval.js +- 58 Length of Last Word.js +- 59 Spiral Matrix II.js +- 61 Rotate List.js +- 62 Unique Paths.js +- 63 Unique Paths II.js +- 64 Minimum Path Sum.js +- 65 Valid Number.js +- 66 Plus One.js +- 67 Add Binary.js +- 68 Text Justification.js +- 69 Sqrt(x).js +- 70 Climbing Stairs.js +- 71 Simplify Path.js +- 72 Edit Distance.js +- 74 Search a 2D Matrix.js +- 75 Sort Colors.js +- 76 Minimum Window Substring.js +- 77 Combinations.js +- 78 Subsets.js +- 79 Word Search.js +- 8 String to Integer (atoi).js +- 80 Remove Duplicates from Sorted Array II.js +- 81 Search in Rotated Sorted Array II.js +- 82 Remove Duplicates from Sorted List II.js +- 83 Remove Duplicates from Sorted List.js +- 84 Largest Rectangle in Histogram.js +- 85 Maximal Rectangle.js +- 86 Partition List.js +- 88 Merge Sorted Array.js +- 89 Gray Code.js +- 9 Palindrome Number.js +- 90 Subsets II.js +- 91 Decode Ways.js +- 92 Reverse Linked List II.js +- 93 Restore IP Addresses.js +- 94 Binary Tree Inorder Traversal.js +- 95 Unique Binary Search Trees II.js +- 96 Unique Binary Search Trees.js +- 98 Validate Binary Search Tree.js +- Basic Calculator II.js +- Basic Calculator III.js +- Bean Probability.js +- Can Win.js +- Conjuct Names With Limit.js +- Convert Binary Search Tree To Doubly Linked List.js +- Convert Infix to Reverse Polish Notation.js +- Custom Tree Problem.js +- Data Structure Max Heap.js +- Data Structure Min Heap.js +- Disambiguos Actors.js +- Find Duplicate Files.js +- Javascript Closure Questions.js +- Log Hits.js +- Longest Common Subsequence.js +- Matrix Diagonal Traversal.js +- Maximum Sum Rectangular Submatrix in Matrix Dynamic Programming:2D.js +- Merge Two Lists Into Sorted List.js +- Min CPU Count.js +- Parse HTML.js +- Parse Log Top k Longest Running Job.js +- Parse String Into Array.js +- README.md +- Ransom Note From Magazine.js +- Rate Limiter.js +- Reverse Integer.js +- Snake And Ladder.js +- String Encoding and Decoding.js +- Top k Longest Running Job.js +- URL shortening.js +- Weighted Job Scheduling.js +- ZigZag Conversion.js +- find kth element in two arrays.js +- flatten nested array.js diff --git a/Ransom Note From Magazine.js b/Ransom Note From Magazine.js new file mode 100644 index 0000000..8f84a34 --- /dev/null +++ b/Ransom Note From Magazine.js @@ -0,0 +1,40 @@ +// Kidnapper kidnaps you and writes a ransom note. He does not write it with hand, as handwriting can put him in, so reaches to a magazine at table and creates ransom note. We need to find out given ransom string and magazine string, is it possible to create given ransom note. Kidnapper can use individual characters of words. + + + +function ransomNoteFromMagazine(magazine, ransom) { + var hash = {}; + var mLen = magazine.length; + var rLen = ransom.length; + var mIdx = 0; + var rIdx = 0; + + while(rIdx < rLen) { + var rc = ransom[rIdx]; + + if(hash[rc] === undefined || hash[rc] === 0) { + var found = false; + + while(mIdx < mLen) { + var mc = magazine[mIdx]; + hash[mc] = hash[mc] || 0; + hash[mc]++; + mIdx++; + + if(mc === rc) { + found = true; + break; + } + } + + if(!found) { + return false; + } + } + + hash[rc]--; + rIdx++; + } + + return true; +} diff --git a/Rate Limiter.js b/Rate Limiter.js new file mode 100644 index 0000000..06a3fd3 --- /dev/null +++ b/Rate Limiter.js @@ -0,0 +1,47 @@ +var RATE = 5; +var PER = 8; +var SECOND_IN_MS = 1000; + +function* RateLimiter(rate, per, cbFunc) { + var lastTime = Date.now(); + var rate = rate; + var per = per; + var allowance = rate; + + + while(true){ + var currentTime = Date.now(); + var elapsedTime = (currentTime - lastTime)/SECOND_IN_MS; + lastTime = currentTime; + allowance += elapsedTime*(rate/per); + + + if(allowance > rate) { + allowance = rate; + } + + if(allowance < 1.0) { + yield cbFunc(false); + } else { + allowance -= 1; + yield cbFunc(true); + } + } +} + +var rl = RateLimiter(RATE, PER, function(output){ + console.log(output) +}); + +rl.next(); +rl.next(); +rl.next(); +rl.next(); +rl.next(); + +rl.next(); + +setTimeout(()=>{ + rl.next(); + rl.next(); +},PER/RATE*SECOND_IN_MS); \ No newline at end of file diff --git a/Reverse Integer.js b/Reverse Integer.js new file mode 100644 index 0000000..d9a8edb --- /dev/null +++ b/Reverse Integer.js @@ -0,0 +1,25 @@ +/** + * @param {number} x + * @return {number} + */ +var reverse = function(x) { + var isNeg = x < 0; + var result = 0; + + x = Math.abs(x); + + while(x) { + var lastDigit = x%10; + result *= 10; + result += lastDigit; + x = parseInt(x/10); + } + + result = isNeg ? -result : result; + + if(result > Math.pow(2,31) - 1 || result < -Math.pow(2,31)) { + return 0; + } + + return result; +}; \ No newline at end of file diff --git a/Snake And Ladder.js b/Snake And Ladder.js new file mode 100644 index 0000000..437356e --- /dev/null +++ b/Snake And Ladder.js @@ -0,0 +1,69 @@ +// Snake and Ladder Problem +// Given a snake and ladder board, find the minimum number of dice throws required to reach the destination or last cell from source or 1st cell. Basically, the player has total control over outcome of dice throw and wants to find out minimum number of throws required to reach last cell. + +// If the player reaches a cell which is base of a ladder, the player has to climb up that ladder and if reaches a cell is mouth of the snake, has to go down to the tail of snake without a dice throw. + +// snakesladders + +// For example consider the board shown on right side (taken from here), the minimum number of dice throws required to reach cell 30 from cell 1 is 3. Following are steps. + +// a) First throw two on dice to reach cell number 3 and then ladder to reach 22 +// b) Then throw 6 to reach 28. +// c) Finally through 2 to reach 30. + +// There can be other solutions as well like (2, 2, 6), (2, 4, 4), (2, 3, 5).. etc. + + + +function snakeAndLadder(moves, n){ + var visited = Array(n).fill(false); + visited[0] = true; + var queue = []; + queue.push(0); + + var dist = 0; + + while(queue.length > 0) { + var len = queue.length; + + for(var j = 0; j < len; j++) { + var move = queue.shift(); + + if(move === n - 1) { + return dist; + } + + for(var i = move + 1; i <= move + 6; i++) { + + if(!visited[i]) { + visited[i] = true; + + if(moves[i] !== -1) { + newMove = moves[i]; + } else { + newMove = i; + } + + queue.push(newMove); + } + } + } + + dist++; + } + + return -1; +} + +var moves = []; +var n = 100; +for(var i = 0; i < n; i++){ + moves.push(-1); +} + +moves[2] = 53; +moves[41] = 99; +moves[54] = 40; + + +console.log(snakeAndLadder(moves, n)); \ No newline at end of file diff --git a/String Encoding and Decoding.js b/String Encoding and Decoding.js new file mode 100644 index 0000000..26c35e4 --- /dev/null +++ b/String Encoding and Decoding.js @@ -0,0 +1,30 @@ +public class Codec { + + // Encodes a list of strings to a single string. + public String encode(List strs) { + StringBuilder output = new StringBuilder(); + for(String str : strs){ + // 对于每个子串,先把其长度放在前面,用#隔开 + output.append(String.valueOf(str.length())+"#"); + // 再把子串本身放在后面 + output.append(str); + } + return output.toString(); + } + + // Decodes a single string to a list of strings. + public List decode(String s) { + List res = new LinkedList(); + int start = 0; + while(start < s.length()){ + // 找到从start开始的第一个#,这个#前面是长度 + int idx = s.indexOf('#', start); + int size = Integer.parseInt(s.substring(start, idx)); + // 根据这个长度截取子串 + res.add(s.substring(idx + 1, idx + size + 1)); + // 更新start为子串后面一个位置 + start = idx + size + 1; + } + return res; + } +} \ No newline at end of file diff --git a/Top k Longest Running Job.js b/Top k Longest Running Job.js new file mode 100644 index 0000000..b1fd1b1 --- /dev/null +++ b/Top k Longest Running Job.js @@ -0,0 +1,17 @@ +// parse log。 +// log是指进程运行的记录。一个进程有一个jobname。由于可以并行多次执行 +// 一个jobname下可以有多个jobid。每个jobid会有一个endtime。 +// 函数,print out 前k个运行时间最长的进程的jobname和对应的最长endtime。 + + +// jobname, jobid, endtime + +// hash1: jobname->endtime: +// store the longest endtime for that job +// hash2: jobid->jobname +// not sure what it's for + +// use min heap to store the top k longest running one + + + diff --git a/URL shortening.js b/URL shortening.js new file mode 100644 index 0000000..078fe71 --- /dev/null +++ b/URL shortening.js @@ -0,0 +1,30 @@ +// http://www.hiredintech.com/system-design/the-system-design-process/ + + + + + +Use Cases: + +1. shortening: take url => return a shorter url +2. redirection: take a short url => redirect to the original url + +high availability of the system + +traffic? + +how many request per sec? +how many new url per sec? + +10% shortening 90% from redirection + +data? + + + +out of scope +3. custom url +4. analytics +5. automatic link expriation +6. manual link removal +7. UI vs API \ No newline at end of file diff --git a/Weighted Job Scheduling.js b/Weighted Job Scheduling.js new file mode 100644 index 0000000..3fe5a14 --- /dev/null +++ b/Weighted Job Scheduling.js @@ -0,0 +1,88 @@ +// C++ program for weighted job scheduling using Dynamic +// Programming and Binary Search +#include +#include +using namespace std; + +// A job has start time, finish time and profit. +struct Job +{ + int start, finish, profit; +}; + +// A utility function that is used for sorting events +// according to finish time +bool myfunction(Job s1, Job s2) +{ + return (s1.finish < s2.finish); +} + +// A Binary Search based function to find the latest job +// (before current job) that doesn't conflict with current +// job. "index" is index of the current job. This function +// returns -1 if all jobs before index conflict with it. +// The array jobs[] is sorted in increasing order of finish +// time. +int binarySearch(Job jobs[], int index) +{ + // Initialize 'lo' and 'hi' for Binary Search + int lo = 0, hi = index - 1; + + // Perform binary Search iteratively + while (lo <= hi) + { + int mid = (lo + hi) / 2; + if (jobs[mid].finish <= jobs[index].start) + { + if (jobs[mid + 1].finish <= jobs[index].start) + lo = mid + 1; + else + return mid; + } + else + hi = mid - 1; + } + + return -1; +} + +// The main function that returns the maximum possible +// profit from given array of jobs +int findMaxProfit(Job arr[], int n) +{ + // Sort jobs according to finish time + sort(arr, arr+n, myfunction); + + // Create an array to store solutions of subproblems. table[i] + // stores the profit for jobs till arr[i] (including arr[i]) + int *table = new int[n]; + table[0] = arr[0].profit; + + // Fill entries in table[] using recursive property + for (int i=1; i 4 -> 3) + (5 -> 6 -> 4) +// Output: 7 -> 0 -> 8 + +// Amazon Microsoft Bloomberg Airbnb Adobe + +/** + * Definition for singly-linked list. + * function ListNode(val) { + * this.val = val; + * this.next = null; + * } + */ +/** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ + + + +// value reverse helps to asslign the first digit or both linklist +var addTwoNumbers = function(l1, l2) { + const answer = new ListNode(0); + var node = answer; + var carry = 0; + while(l1 !== null || l2 !== null || carry !== 0) { + var val = 0; + if (carry !== 0) { + val += carry; + } + carry = 0; + if (l1 !== null) { + val += l1.val; + } + if (l2 !== null) { + val += l2.val; + } + if (val > 9) { + val -= 10; + carry = 1; + } + node.next = new ListNode(val); + node = node.next; + if (l1 !== null) { + l1 = l1.next; + } + if (l2 !== null) { + l2 = l2.next; + } + } + + return answer.next; +}; diff --git a/3 Longest Substring Without Repeating Characters.js b/[0003] Longest Substring Without Repeating Characters.js similarity index 51% rename from 3 Longest Substring Without Repeating Characters.js rename to [0003] Longest Substring Without Repeating Characters.js index 2405d30..d917b15 100644 --- a/3 Longest Substring Without Repeating Characters.js +++ b/[0003] Longest Substring Without Repeating Characters.js @@ -2,6 +2,11 @@ * @param {string} s * @return {number} */ + + +// use map for storing index +// if a repeated character is found, skip directly to the index of the repeated character in the map. + var lengthOfLongestSubstring = function(s) { if(s === null || s.length === 0){ return 0; @@ -11,16 +16,17 @@ var lengthOfLongestSubstring = function(s) { var len = 0; var maxLen = len; var start = 0; - + + // scan from left to right. for(var i = start; i < s.length; i++){ c = s[i]; if(map[c] !== undefined && map[c] >= start) { - start = map[c] + 1; - len = i - start; + start = map[c] + 1; // start new search with repeated word's last location + 1 + len = i - start; // real length -> from for example 3 to 5 is 3, so it's 5-3+1 and + 1 happens later } - len++; + len++; // real length -> from for example 3 to 5 is 3, so it's 5-3+1 and + 1 happens later if(len > maxLen){ maxLen = len; diff --git a/[0004] Median of Two Sorted Arrays.js b/[0004] Median of Two Sorted Arrays.js new file mode 100644 index 0000000..33e7fb2 --- /dev/null +++ b/[0004] Median of Two Sorted Arrays.js @@ -0,0 +1,146 @@ +// /** +// * @param {number[]} nums1 +// * @param {number[]} nums2 +// * @return {number} +// */ + +// // http://blog.csdn.net/yutianzuijin/article/details/11499917 +// var findMedianSortedArrays = function(nums1, nums2) { +// var m = nums1.length; +// var n = nums2.length; +// var total = m + n; + +// if(total%2 === 1) { +// return findKth(nums1, m, nums2, n, parseInt(total/2) + 1); +// } else { +// return (findKth(nums1, m, nums2, n, parseInt(total/2)) + findKth(nums1, m, nums2, n, parseInt(total/2) + 1))/2; +// } +// }; + + +// function findKth(a, m, b, n, k) { +// // always assume that m is equal or smaller than n +// if(m > n) { +// return findKth(b, n, a, m, k); +// } + +// if(m === 0) { +// return b[k-1]; +// } + +// if(k === 1) { +// return Math.min(a[0],b[0]); +// } + +// // divide k into two parts +// var pa = Math.min(parseInt(k/2), m); +// var pb = k - pa; + +// if(a[pa - 1] < b[pb - 1]) { +// return findKth(a.slice(pa), m - pa, b, n, k - pa); +// } else if(a[pa - 1] > b[pb - 1]) { +// return findKth(a, m, b.slice(pb), n - pb, k - pb); +// } else { +// return a[pa - 1]; +// } +// } + + +// /** +// * @param {number[]} nums1 +// * @param {number[]} nums2 +// * @return {number} +// */ +// var findMedianSortedArrays = function(nums1, nums2) { +// var total = nums1.length + nums2.length; +// +// if (total % 2 === 1) { +// return findKth(nums1, 0, nums2, 0, parseInt(total/2) + 1); +// } else { +// return ( +// findKth(nums1, 0, nums2, 0, parseInt(total/2)) +// + findKth(nums1, 0, nums2, 0, parseInt(total/2) + 1) +// )/2; +// } +// }; +// +// function findKth(nums1, start1, nums2, start2, kth) { +// var len1 = nums1.length - start1; +// var len2 = nums2.length - start2; +// +// if (len1 > len2) { +// return findKth(nums2, start2, nums1, start1, kth); +// } +// +// if (len1 === 0) { +// return nums2[kth - 1]; +// } +// +// if (kth === 1) { +// return Math.min(nums1[start1], nums2[start2]); +// } +// +// // divide kth into 2 parts +// var part1 = Math.min(parseInt(kth/2), len1); +// var part2 = kth - part1; +// +// if (nums1[start1 + part1 - 1] < nums2[start2 + part2 - 1]) { +// return findKth(nums1, start1 + part1, nums2, start2, kth - part1); +// } else if (nums1[start1 + part1 - 1] > nums2[start2 + part2 - 1]) { +// return findKth(nums1, start1, nums2, start2 + part2, kth - part2); +// } else { +// return nums1[start1 + part1 - 1]; +// } +// } + + + +/** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @return {number} + */ +var findMedianSortedArrays = function(nums1, nums2) { + const len = nums1.length + nums2.length; + + if (len % 2 === 1) { + return findKth(nums1, 0, nums2, 0, Math.floor(len/2) + 1); + } else { + const first = findKth(nums1, 0, nums2, 0, Math.floor(len/2)); + const second = findKth(nums1, 0, nums2, 0, Math.floor(len/2) + 1); + + return (first + second) / 2; + } +}; + +function findKth(nums1, start1, nums2, start2, kth) { + const len1 = nums1.length - start1; + const len2 = nums2.length - start2; + + if (len1 > len2) { + return findKth(nums2, start2, nums1, start1, kth); + } + + if (len1 === 0) { + return nums2[kth - 1]; + } + + if (kth === 1) { + return Math.min(nums1[start1], nums2[start2]); + } + + // Three conditions here, len1 < kth/2, len1 === kth/2, len1 > kth/2 + const kth1 = Math.min(Math.floor(kth/2), len1); + const kth2 = kth - kth1; + + const nums1Kth = nums1[start1 + kth1 - 1]; + const nums2Kth = nums2[start2 + kth2 - 1]; + + if (nums1Kth < nums2Kth) { + return findKth(nums1, start1 + kth1, nums2, start2, kth2); + } else if (nums1Kth > nums2Kth) { + return findKth(nums1, start1, nums2, start2 + kth2, kth1); + } else { + return nums1Kth; + } +} diff --git a/[0004] Median of Two Sorted Arrays.sublime-workspace b/[0004] Median of Two Sorted Arrays.sublime-workspace new file mode 100644 index 0000000..4942cb0 --- /dev/null +++ b/[0004] Median of Two Sorted Arrays.sublime-workspace @@ -0,0 +1,239 @@ +{ + "auto_complete": + { + "selected_items": + [ + [ + "atta", + "attachEvent" + ] + ] + }, + "buffers": + [ + ], + "build_system": "", + "build_system_choices": + [ + ], + "build_varint": "", + "command_palette": + { + "height": 87.0, + "last_filter": "", + "selected_items": + [ + [ + "package install", + "Package Control: Install Package" + ], + [ + "package install ", + "Package Control: Install Package" + ], + [ + "package insta", + "Package Control: Install Package" + ], + [ + "package", + "Install Package Control" + ] + ], + "width": 485.0 + }, + "console": + { + "height": 0.0, + "history": + [ + ] + }, + "distraction_free": + { + "menu_visible": true, + "show_minimap": false, + "show_open_files": false, + "show_tabs": false, + "side_bar_visible": false, + "status_bar_visible": false + }, + "file_history": + [ + "/Users/cyu0/workspace/perkmon/src/routes/home/Home.js", + "/Users/cyu0/workspace/perkmon/src/routes/home/Home.css", + "/Users/cyu0/Downloads/immutable-js-diff-master/tests/sequenceDiff.test.js", + "/Users/cyu0/workspace/perkmon/src/components/Input/Input.css", + "/Users/cyu0/workspace/perkmon/src/components/Html.js", + "/Users/cyu0/workspace/perkmon/src/components/Input/Input.js", + "/Users/cyu0/workspace/perkmon/src/components/SearchWithBgImage/SearchWithBgImage.css", + "/Users/cyu0/workspace/perkmon/src/components/App.js", + "/Users/cyu0/workspace/perkmon/src/lib/event.js", + "/Users/cyu0/workspace/perkmon/src/lib/Event.js", + "/Users/cyu0/workspace/perkmon/src/components/CtaImageWithSearch/SearchWithBgImage.js", + "/Users/cyu0/workspace/perkmon/src/components/CtaImageWithSearch/SearchWithBgImage.css", + "/Users/cyu0/workspace/perkmon/src/components/Header/Header.css", + "/Users/cyu0/workspace/perkmon/src/routes/home/index.js", + "/Users/cyu0/workspace/perkmon/src/components/Header/Header.js", + "/Users/cyu0/workspace/perkmon/src/routes/index.js", + "/Users/cyu0/workspace/perkmon/build/server.js", + "/Users/cyu0/workspace/perkmon/src/", + "/Users/cyu0/workspace/perkmon/src/components/Navigation/Navigation.js", + "/Users/cyu0/workspace/perkmon/node_modules/enzyme/src/ReactWrapper.jsx", + "/Users/cyu0/workspace/perkmon/node_modules/resolve/test/precedence/aaa.js", + "/Users/cyu0/workspace/perkmon/src/components/variables.css", + "/Users/cyu0/workspace/perkmon/package.json" + ], + "find": + { + "height": 24.0 + }, + "find_in_files": + { + "height": 93.0, + "where_history": + [ + ] + }, + "find_state": + { + "case_sensitive": false, + "find_history": + [ + ], + "highlight": true, + "in_selection": false, + "preserve_case": false, + "regex": false, + "replace_history": + [ + ], + "reverse": false, + "show_context": true, + "use_buffer2": true, + "whole_word": false, + "wrap": true + }, + "groups": + [ + { + "sheets": + [ + ] + } + ], + "incremental_find": + { + "height": 24.0 + }, + "input": + { + "height": 31.0 + }, + "layout": + { + "cells": + [ + [ + 0, + 0, + 1, + 1 + ] + ], + "cols": + [ + 0.0, + 1.0 + ], + "rows": + [ + 0.0, + 1.0 + ] + }, + "menu_visible": true, + "output.SublimeLinter": + { + "height": 0.0 + }, + "output.SublimeLinter Messages": + { + "height": 108.0 + }, + "output.find_results": + { + "height": 0.0 + }, + "pinned_build_system": "", + "project": "[0004] Median of Two Sorted Arrays.sublime-project", + "replace": + { + "height": 44.0 + }, + "save_all_on_build": true, + "select_file": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + [ + "header.css", + "src/components/Header/Header.css" + ], + [ + "navigation", + "src/components/Navigation/Navigation.js" + ], + [ + "variables.css", + "src/components/variables.css" + ], + [ + "aa.js", + "node_modules/resolve/test/precedence/aaa.js" + ], + [ + ".jsx", + "node_modules/enzyme/src/ReactWrapper.jsx" + ], + [ + ".json", + "package.json" + ] + ], + "width": 0.0 + }, + "select_project": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + ], + "width": 0.0 + }, + "select_symbol": + { + "height": 0.0, + "last_filter": "", + "selected_items": + [ + ], + "width": 0.0 + }, + "selected_group": 0, + "settings": + { + }, + "show_minimap": true, + "show_open_files": false, + "show_tabs": true, + "side_bar_visible": true, + "side_bar_width": 300.0, + "status_bar_visible": true, + "template_settings": + { + } +} diff --git a/[0010] Regular Expresion Matching.js b/[0010] Regular Expresion Matching.js new file mode 100644 index 0000000..ca77413 --- /dev/null +++ b/[0010] Regular Expresion Matching.js @@ -0,0 +1,73 @@ +// https://www.youtube.com/watch?v=l3hda49XcDE#t=211.113333 + +// Implement regular expression matching with support for '.' and '*'. + +// '.' Matches any single character. +// '*' Matches zero or more of the preceding element. + +// The matching should cover the entire input string (not partial). + +// The function prototype should be: +// bool isMatch(const char *s, const char *p) + +// Some examples: +// isMatch("aa","a") → false +// isMatch("aa","aa") → true +// isMatch("aaa","aa") → false +// isMatch("aa", "a*") → true +// isMatch("aa", ".*") → true +// isMatch("ab", ".*") → true +// isMatch("aab", "c*a*b") → true + +/** + * @param {string} s + * @param {string} p + * @return {boolean} + */ +var isMatch = function(s, p) { + var sLen = s.length; + var pLen = p.length; + var dp = []; + + for(var i = 0; i <= sLen; i++) { + var tmp = []; + + for(var j = 0; j <= pLen; j++) { + tmp.push(false); + } + + dp.push(tmp); + } + + dp[0][0] = true; + + for(i = 0; i <= sLen; i++) { + for(j = 0; j <= pLen; j++) { + if(p[j - 1] !== '.' && p[j - 1] !== '*') { + if(i > 0 && p[j - 1] === s[i - 1] && dp[i - 1][j - 1]) { + dp[i][j] = true; + } + } else if(p[j - 1] === '.') { + if(i > 0 && dp[i - 1][j - 1]) { + dp[i][j] = true; + } + } else if(j > 1) { // '*' cannot be the first element + if(dp[i][j - 2]) { // 0 occurance + dp[i][j] = true; + } else if(i > 0 && (p[j - 2] === s[i - 1] || p[j - 2] === '.') && dp[i - 1][j]) { + + // example + // xa and xa* + // s[i-1] === a + // p[j-2] === a + // a === a + // so we can now compare x, xa* + // and x here is dp[i-1][j] + dp[i][j] = true; + } + } + } + } + + return dp[sLen][pLen]; +}; \ No newline at end of file diff --git a/find kth element in two arrays.js b/find kth element in two arrays.js new file mode 100644 index 0000000..6c635f7 --- /dev/null +++ b/find kth element in two arrays.js @@ -0,0 +1,59 @@ +var findKth = (a1, a2, kth) => { + var alen1 = a1.length; + var alen2 = a2.length; + + if(alen1 > alen2) { + return findKth(a2, a1, kth); + } + + if(alen1 === 0) { + return a2[kth -1]; + } + + if(kth === 1) { + return Math.min(a1[0], a2[0]); + } + +// need to make sure that kth is not 1 as kth/2 = 0 + var p1 = Math.min(parseInt(kth/2), alen1); + var p2 = kth - p1; + + if(a1[p1 - 1] < a2[p2 - 1]) { + return findKth(a1.slice(p1), a2, kth - p1); + } else if(a1[p1 - 1] > a2[p2 - 1]) { + return findKth(a1, a2.slice(p2), kth - p2); + } else { + return a1[p1 - 1]; + } +} + + +// function findKth(a, aStart, aEnd, b, bStart, bEnd, kth) { +// // use array position rather than use slice to get array +// // always assume that m is equal or smaller than n +// var aLen = aEnd - aStart + 1; // same as a.length as index 3 - 3 = 0 but still it has one element compared to a.length === 0 has notthing +// var bLen = bEnd - bStart + 1; +// var mid; +// if(aLen > bLen) { +// return findKth(b, bStart, bEnd, a, aStart, aEnd, kth); +// } + +// if(aLen <= 0) { +// return b[kth - 1]; +// } + +// if(kth === 1) { +// return Math.min(a[aStart], b[bStart]); +// } + +// var k1 = Math.min(parseInt(kth/2), aLen); +// var k2 = kth - k1; + +// if(a[aStart + k1 - 1] < b[bStart + k2 - 1]) { +// return findKth(a, aStart + k1, aEnd, b, bStart, bEnd, kth -k1); +// } else if(a[aStart + k1 - 1] > b[bStart + k2 - 1]) { +// return findKth(a, aStart, aEnd, b, bStart + k2, bEnd, kth -k2); +// } else { +// return a[aStart + k1 -1]; +// } +// } \ No newline at end of file diff --git a/flatten nested array.js b/flatten nested array.js new file mode 100644 index 0000000..21b9488 --- /dev/null +++ b/flatten nested array.js @@ -0,0 +1,24 @@ +var arr = [1,2,[3,4,[5,[6]],7],8,9]; + +function flatten(arr) { + return arr.reduce(function(self, el){ + var items = Array.isArray(el) ? flatten(el) : [el]; + return self.concat(items); + }, []); +} + +function flatten(array, result) { + result === undefined && (result = []); + + for (var i = 0, len = array.length; i < len; i++) { + if (Object.prototype.toString.call(array[i]) === '[object Array]') { + flatten(array[i], result); + } else { + result.push(array[i]); + } + } + + return result; +} + +console.log(flatten(arr)); \ No newline at end of file diff --git a/key concepts b/key concepts new file mode 100644 index 0000000..b8f94bd --- /dev/null +++ b/key concepts @@ -0,0 +1,3 @@ +1. Substring vs subsequnce: substrings are consecutive subsequences +2. substring without repeating character: use map for storing index and use time window +