├── 10. Regular Expression Matching.java ├── 102. Binary Tree Level Order Traversal.java ├── 121. Best Time to Buy and Sell Stock.java ├── 125. Valid Palindrome.java ├── 133. Clone Graph.java ├── 138. Copy List with Random Pointer.java ├── 139. Word Break.java ├── 151. Reverse Words in a String.java ├── 152. Maximum Product Subarray.java ├── 161. One Edit Distance.java ├── 17. Letter Combinations of a Phone Number.java ├── 173. Binary Search Tree Iterator.java ├── 200. Number of Islands.java ├── 206. Reverse Linked List.java ├── 211. Add and Search Word - Data structure design.java ├── 215. Kth Largest Element in an Array.java ├── 221. Maximal Square.java ├── 230. Kth Smallest Element in a BST.java ├── 235. Lowest Common Ancestor of Binary Search Tree.java ├── 253. Meeting Rooms II.java ├── 257. Binary Tree Paths.java ├── 261. Graph Valid Tree.java ├── 273. Integer to English Words.java ├── 277. Find the Celebrity.java ├── 278. First Bad Version.java ├── 28. Implement strStr().java ├── 282. Expression Add Operators.java ├── 283. Move Zeroes.java ├── 285. Inorder Successor in BST.java ├── 29. Divide Two Integers.java ├── 295. Find Median from Data Stream.java ├── 297. Serialize and Deserialize Binary Tree.java ├── 300. Longest Increasing Subsequence.java ├── 301. Remove Invalid Parentheses.java ├── 314. Binary Tree Vertical Order Traversal.java ├── 33. Search in Rotated Sorted Array.java ├── 334. Increasing Triplet Subsequence.java ├── 340. Longest Substring with At Most K Distinct Cha.java ├── 377. Combination Sum IV.java ├── 38. Count and Say.java ├── 380. Insert Delete GetRandom O(1).java ├── 394. Decode String.java ├── 398. Random Pick Index.java ├── 43. Multiply Strings.java ├── 49. Group Anagrams.java ├── 494. TargetSum.java ├── 56. Merge Intervals.java ├── 57. Insert Interval.java ├── 67. Add Binary.java ├── 75. Sort Colors.java ├── 76. Minimum Window Substring.java ├── 90. Subsets II.java ├── 91. Decode Ways.java ├── 98. Validate Binary Search Tree.java ├── Behavior.txt ├── Bipartite Graph.java ├── Can Reach (m,n).java ├── Construct BST from preorder list.java ├── Convert BST to Circular Doubly LinkedList.java ├── Count Palindromic Substrings.java ├── Dot Product & Variations.java ├── Find 1st Different Leaf in BST given 2 Preorder arrays.java ├── Find K Closest Points.java ├── Friend Recommendation.java ├── K Sum.java ├── Least Removal to Valid Palindromic Subsequence.java ├── LinkedList with Peek & Pop.java ├── Longest Arithmetic Subsequence.java ├── Longest Crossing Road.java ├── Longest Path in Binary Tree.java ├── Merge K Sorted Lists : Array.java ├── Mine Sweeper.java ├── Momotonous Array.java ├── Most Frequenct Character in a String.java ├── Power Mod.java ├── Previous Permutation.java ├── Print All Paths in a 2D Board.java ├── README.md ├── Random return number according to weight.java ├── Random subset of size K.java ├── Reader Writer Problem.java ├── Run Length Encoding.java ├── Shifting Matrix.java ├── Shortest Knight Move.java ├── Sort Squared Sorted Array.java ├── Sparce Matrix Multiplication.java ├── Subarray Sum.java ├── Swap Sort.java └── Task schedule with cool down time.java /10. Regular Expression Matching.java: -------------------------------------------------------------------------------- 1 | 10. Regular Expression Matching 2 | 3 | '.' Matches any single character. 4 | '*' Matches zero or more of the preceding element. 5 | The matching should cover the entire input string (not partial). 6 | Some examples: 7 | isMatch("aa","a") → false 8 | isMatch("aa","aa") → true 9 | isMatch("aaa","aa") → false 10 | isMatch("aa", "a*") → true 11 | isMatch("aa", ".*") → true 12 | isMatch("ab", ".*") → true 13 | isMatch("aab", "c*a*b") → true 14 | 15 | 我说DP,但他偏说喜欢递归。。。幸好时间 多 ,没让写代码, 从 没写过递归版本的。。。 16 | 17 | Solution: DP 18 | [YouTube] // https://www.youtube.com/watch?v=l3hda49XcDE 19 | 20 | dp[i][j] = dp[i - 1][j - 1] , p(j - 1) != '*' && s(i - 1) = p(j - 1) 21 | = dp[i][j - 2] , p(j - 1) == '*' && matches empty 22 | = dp[i - 1][j] , p(j - 1) == '*' && s(i - 1) = p(j - 2), 'x' repeats >= 1 times 23 | 24 | public boolean isMatch(String s, String p) { 25 | int m = s.length(), n = p.length(); 26 | boolean[][] dp = new boolean[m + 1][n + 1]; 27 | dp[0][0] = true; 28 | // p[0.., j - 3, j - 2, j - 1] matches empty iff p[j - 1] is '*' and p[0..j - 3] matches empty 29 | for (int j = 1; j < n; j += 2) 30 | if (p.charAt(j) == '*') dp[0][j + 1] = dp[0][j - 1]; 31 | for (int i = 1; i <= m; i++) 32 | for (int j = 1; j <= n; j++) 33 | if (p.charAt(j - 1) != '*') 34 | dp[i][j] = dp[i - 1][j - 1] && isCharMatch(s.charAt(i - 1), p.charAt(j - 1)); 35 | else 36 | dp[i][j] = dp[i][j - 2] || dp[i - 1][j] && isCharMatch(s.charAt(i - 1), p.charAt(j - 2)); 37 | return dp[m][n]; 38 | } 39 | private boolean isCharMatch(char s, char p) { 40 | return p == '.' || s == p; 41 | } 42 | 43 | 44 | ******************************Follow Up: 优化空间******************************* 45 | 46 | public boolean isMatch(String s, String p) { 47 | int m = s.length(), n = p.length(); 48 | boolean[] dp = new boolean[n + 1]; 49 | dp[0] = true; 50 | for (int j = 1; j < n; j += 2) 51 | if (p.charAt(j) == '*') dp[j + 1] = dp[j - 1]; 52 | for (int i = 1; i <= m; i++) { 53 | boolean pre = dp[0]; 54 | dp[0] = false; 55 | for (int j = 1; j <= n; j++) { 56 | boolean tmp = dp[j]; 57 | if (p.charAt(j - 1) != '*') 58 | dp[j] = pre && isCharMatch(s.charAt(i - 1), p.charAt(j - 1)); 59 | else 60 | dp[j] = dp[j - 2] || dp[j] && isCharMatch(s.charAt(i - 1), p.charAt(j - 2)); 61 | pre = tmp; 62 | } 63 | } 64 | return dp[n]; 65 | } 66 | 67 | 68 | 69 | 70 | ----------------------- 71 | 72 | 44. Wildcard Matching 73 | 74 | We define the state P[i][j] to be whether s[0..i) matches p[0..j). The state equations are as follows: 75 | P[i][j] = P[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '?'), if p[j - 1] != '*'; 76 | P[i][j] = P[i][j - 1] || P[i - 1][j], if p[j - 1] == '*'. 77 | 78 | // Equation 1). means that if p[j-1] is not *, f(i,j) is determined by if s[0:i-2] matches p[0:j-2] and if (s[i-1]==p[j-1] or p[j-1]=='?'). 79 | // Equation 2). means that if p[j-1] is *, f(i,j) is true if either f(i,j-1) is true: s[0:i-1] matches p[0:j-2] and * is not used here; 80 | // or f(i-1,j) is true: s[0:i-2] matches p[0:j-1] and * is used to match s[i-1]. 81 | 82 | public boolean isMatch(String s, String p) { 83 | int m = s.length(), n = p.length(); 84 | boolean[][] dp = new boolean[m + 1][n + 1]; 85 | dp[0][0] = true; 86 | for(int j = 1; j <= n && p.charAt(j-1) == '*'; j++) 87 | dp[0][j] = true; 88 | for (int i = 1; i <= m; i++) 89 | for (int j = 1; j <= n; j++) 90 | if (p.charAt(j - 1) != '*') 91 | dp[i][j] = dp[i - 1][j - 1] && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?'); 92 | else 93 | dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; 94 | return dp[m][n]; 95 | } 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /102. Binary Tree Level Order Traversal.java: -------------------------------------------------------------------------------- 1 | 102. Binary Tree Level Order Traversal 2 | 3 | Solution 1: BFS 4 | Time: O(n) 5 | 6 | public List> levelOrder(TreeNode root) { 7 | List> res = new ArrayList<>(); 8 | if (root == null) return res; 9 | Queue queue = new LinkedList<>(); 10 | queue.offer(root); 11 | while (!queue.isEmpty()) { 12 | List tmp = new ArrayList<>(); 13 | int size = queue.size(); 14 | for (int i = 0; i < size; i++) { 15 | TreeNode node = queue.poll(); 16 | tmp.add(node.val); 17 | if (node.left != null) queue.offer(node.left); 18 | if (node.right != null) queue.offer(node.right); 19 | } 20 | res.add(tmp); 21 | } 22 | return res; 23 | } 24 | 25 | 26 | 27 | 28 | Solution 2: DFS 29 | Time: O(n) 30 | 31 | public List> levelOrder(TreeNode root) { 32 | List> res = new ArrayList>(); 33 | dfs(res, root, 0); 34 | return res; 35 | } 36 | private void dfs(List> res, TreeNode root, int level) { 37 | if (root == null) return; 38 | if (level == res.size()) res.add(new ArrayList<>()); 39 | res.get(level).add(root.val); 40 | dfs(res, root.left, level + 1); 41 | dfs(res, root.right, level + 1); 42 | } 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /121. Best Time to Buy and Sell Stock.java: -------------------------------------------------------------------------------- 1 | 121. Best Time to Buy and Sell Stock 2 | // https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 3 | 4 | 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. 5 | Example 1: 6 | Input: [7, 1, 5, 3, 6, 4] 7 | Output: 5 8 | max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price) 9 | Example 2: 10 | Input: [7, 6, 4, 3, 1] 11 | Output: 0 12 | In this case, no transaction is done, i.e. max profit = 0. 13 | 14 | 15 | Solution 1: kadane algorithm 16 | 17 | public int maxProfit(int[] prices) { 18 | int maxCur = 0, maxSoFar = 0; 19 | for (int i = 1; i > prices.length; i++) { 20 | maxCur = Math.max(0, maxCur + prices[i] - prices[i - 1]); 21 | maxSoFar = Math.max(maxSoFar, maxCur); 22 | } 23 | return maxSoFar; 24 | } 25 | 26 | Solution 2: straight forward 27 | public int maxProfit(int[] prices) { 28 | if (prices == null || prices.length == 0) return 0; 29 | int min = prices[0], res = 0; 30 | for (int i = 1; i < prices.length; i++) 31 | if (prices[i] < min) min = prices[i]; 32 | else res = Math.max(res, prices[i] - min); 33 | return res; 34 | } 35 | 36 | 37 | ------------------------------------------- 38 | 122. Best Time to Buy and Sell Stock II 39 | // https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ 40 | 41 | Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). 42 | However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again). 43 | 44 | 45 | public int maxProfit(int[] prices) { 46 | int max = 0; 47 | for (int i = 1; i < prices.length; i++) 48 | max += Math.max(0, prices[i] - prices[i - 1]); 49 | return max; 50 | } 51 | 52 | 53 | ------------------------------------------- 54 | 123. Best Time to Buy and Sell Stock III 55 | // https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ 56 | 57 | public int maxProfit(int[] prices) { 58 | int oneBuy = Integer.MIN_VALUE, oneBuyOneSell = 0, twoBuy = Integer.MIN_VALUE, twoBuyTwoSell = 0; 59 | for (int p : prices) { 60 | oneBuy = Math.max(oneBuy, -p); 61 | oneBuyOneSell = Math.max(oneBuyOneSell, oneBuy + p); 62 | twoBuy = Math.max(twoBuy, oneBuyOneSell - p); 63 | twoBuyTwoSell = Math.max(twoBuyTwoSell, twoBuy + p); 64 | } 65 | //return Math.max(oneBuyOneSell, twoBuyTwoSell); 66 | return twoBuyTwoSell; 67 | } 68 | 69 | The return statement can just be "return twoBuyTwoSell", since if oneBuyOneSell is the way we make max profit our twoBuyTwoSell will be set to oneBuyOneSell . 70 | But I still keep it to make the logic more clear. 71 | 72 | 73 | ------------------------------------------- 74 | 188. Best Time to Buy and Sell Stock IV 75 | // https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iv/ 76 | Say you have an array for which the ith element is the price of a given stock on day i. 77 | Design an algorithm to find the maximum profit. You may complete at most k transactions. 78 | 79 | Solution: DP 80 | local[i][j] = Math.max(global[i - 1][j - 1] + Math.max(0, prices[j] - prices[j - 1]), local[i][j - 1] + prices[j] - prices[j - 1]); 81 | global[i][j] = Math.max(global[i][j - 1], local[i][j]); 82 | 83 | Time: O(nk) 84 | 85 | [Reference]//https://aaronice.gitbooks.io/lintcode/content/high_frequency/best_time_to_buy_and_sell_stock_iv.html 86 | 87 | public int maxProfit(int k, int[] prices) { 88 | int n = prices.length; 89 | if (n <= 1) return 0; 90 | if (k >= n / 2) { 91 | int max = 0; 92 | for (int i = 1; i < n; i++) 93 | if (prices[i] > prices[i - 1]) 94 | max += prices[i] - prices[i - 1]; 95 | return max; 96 | } 97 | int[][] dp = new int[k + 1][n]; 98 | for (int i = 1; i <= k; i++) { 99 | int local = 0; 100 | for (int j = 1; j < n; j++) { 101 | local = Math.max(dp[i - 1][j - 1] + Math.max(0, prices[j] - prices[j - 1]), local + prices[j] - prices[j - 1]); 102 | dp[i][j] = Math.max(dp[i][j - 1], local); 103 | } 104 | } 105 | return dp[k][n - 1]; 106 | } 107 | 108 | public int maxProfit(int k, int[] prices) { 109 | int n = prices.length; 110 | if (n <= 1) return 0; 111 | if (k >= n / 2) { 112 | int max = 0; 113 | for (int i = 1; i < n; i++) 114 | if (prices[i] > prices[i - 1]) 115 | max += prices[i] - prices[i - 1]; 116 | return max; 117 | } 118 | int[][] global = new int[k + 1][n]; 119 | int[][] local = new int[k + 1][n]; 120 | for (int i = 1; i <= k; i++) { 121 | int local = 0; 122 | for (int j = 1; j < n; j++) { 123 | local[i][j] = Math.max(global[i - 1][j - 1] + Math.max(0, prices[j] - prices[j - 1]), local[i][j - 1] + prices[j] - prices[j - 1]); 124 | global[i][j] = Math.max(global[i][j - 1], local[i][j]); 125 | } 126 | } 127 | return global[k][n - 1]; 128 | } 129 | 130 | 131 | 132 | ------------------------------------------- 133 | 309. Best Time to Buy and Sell Stock with Cooldown 134 | // https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/ 135 | 136 | Solution: DP 137 | buy[i] = Math.max(buy[i - 1], sell[i - 2] - prices[i]); 138 | sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i]); 139 | 140 | public int maxProfit(int[] prices) { 141 | int prev_sell = 0, sell = 0, prev_buy = Integer.MIN_VALUE, buy = prev_buy; 142 | for (int p : prices) { 143 | prev_buy = buy; // prev_buy : buy[i - 1] 144 | buy = Math.max(prev_buy, prev_sell - p); // prev_sell : sell[i - 2] 145 | prev_sell = sell; // prev_sell : sell[i - 1] 146 | sell = Math.max(prev_sell, prev_buy + p); // prev_buy : buy[i - 1] 147 | } 148 | return sell; 149 | } 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | -------------------------------------------------------------------------------- /125. Valid Palindrome.java: -------------------------------------------------------------------------------- 1 | 125. Valid Palindrome 2 | // https://leetcode.com/problems/valid-palindrome/ 3 | "A man, a plan, a canal: Panama" is a palindrome. 4 | "race a car" is not a palindrome. 5 | 6 | Test: 7 | "" -> true //[加分项:问面试官""应该返回什么] 8 | 9 | public boolean isPalindrome(String s) { 10 | // if (s.equals("")) return true; 11 | char[] chs = s.toCharArray(); 12 | int left = 0, right = s.length() - 1; 13 | while (left <= right) { 14 | while (left < right && !Character.isLetterOrDigit(chs[left])) 15 | left++; 16 | while (left < right && !Character.isLetterOrDigit(chs[right])) 17 | right--; 18 | if (Character.toLowerCase(chs[left++]) != Character.toLowerCase(chs[right--])) 19 | return false; 20 | } 21 | return true; 22 | } -------------------------------------------------------------------------------- /133. Clone Graph.java: -------------------------------------------------------------------------------- 1 | 133. Clone Graph 2 | // https://leetcode.com/problems/clone-graph/ 3 | 4 | Deep Copy 5 | 6 | public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { 7 | Map map = new HashMap<>(); 8 | return dfsClone(node, map); 9 | } 10 | public UndirectedGraphNode dfsClone(UndirectedGraphNode node, Map map) { 11 | if (node == null) return null; 12 | if (map.containsKey(node.label)) return map.get(node.label); 13 | UndirectedGraphNode cloneNode = new UndirectedGraphNode(node.label); 14 | map.put(cloneNode.label, cloneNode); 15 | for (UndirectedGraphNode n : node.neighbors) 16 | cloneNode.neighbors.add(dfsClone(n, map)); 17 | return cloneNode; 18 | } 19 | 20 | 如果图不连通,定义hashset,set 每deep copy完一个,就remove 21 | 22 | -------------------------------------------------------------------------------- /138. Copy List with Random Pointer.java: -------------------------------------------------------------------------------- 1 | 138. Copy List with Random Pointer 2 | 3 | Solution 1: hashmap + 2 iteration 4 | 第一遍deep copy每个node并存hashmap,第二遍根据hashmap来deep copy random指针(注意条件:cur.random != null) 5 | 6 | public RandomListNode copyRandomList(RandomListNode head) { 7 | RandomListNode dummy = new RandomListNode(0), cur = dummy; 8 | Map map = new HashMap<>(); 9 | while (head != null) { 10 | RandomListNode newNode = new RandomListNode(head.label); 11 | map.put(head, newNode); 12 | newNode.random = head.random; 13 | cur.next = newNode; 14 | cur = cur.next; 15 | head = head.next; 16 | } 17 | cur = dummy.next; 18 | while (cur != null) { 19 | if (cur.random != null) 20 | cur.random = map.get(cur.random); 21 | cur = cur.next; 22 | } 23 | return dummy.next; 24 | } 25 | 26 | 27 | Solution 2: hashmap + 1 iteration 28 | 29 | public RandomListNode copyRandomList(RandomListNode head) { 30 | RandomListNode dummy = new RandomListNode(0), cur = dummy; 31 | Map map = new HashMap<>(); 32 | while (head != null) { 33 | RandomListNode newNode = null; 34 | if (map.containsKey(head)) 35 | newNode = map.get(head); 36 | else { 37 | newNode = new RandomListNode(head.label); 38 | map.put(head, newNode); 39 | } 40 | if (head.random != null) // ATTENTION 41 | if (map.containsKey(head.random)) 42 | newNode.random = map.get(head.random); 43 | else { 44 | newNode.random = new RandomListNode(head.random.label); 45 | map.put(head.random, newNode.random); 46 | } 47 | cur.next = newNode; 48 | cur = cur.next; 49 | head = head.next; 50 | } 51 | return dummy.next; 52 | } 53 | 54 | 55 | Solution 3: copy -> random -> split 56 | Space: O(1) 57 | 58 | public RandomListNode copyRandomList(RandomListNode head) { 59 | if (head == null) return null; 60 | RandomListNode cur = head; 61 | while (cur != null) { 62 | RandomListNode newNode = new RandomListNode(cur.label); 63 | newNode.next = cur.next; 64 | cur.next = newNode; 65 | cur = cur.next.next; 66 | } 67 | cur = head; 68 | while (cur != null) { 69 | if (cur.random != null) 70 | cur.next.random = cur.random.next; 71 | cur = cur.next.next; 72 | } 73 | cur = head; 74 | RandomListNode newHead = head.next; 75 | while (cur != null) { 76 | RandomListNode newNode = cur.next; 77 | cur.next = newNode.next; 78 | cur = cur.next; 79 | if (cur != null) newNode.next = cur.next; 80 | } 81 | return newHead; 82 | } 83 | -------------------------------------------------------------------------------- /139. Word Break.java: -------------------------------------------------------------------------------- 1 | 139. Word Break 2 | // https://leetcode.com/problems/word-break/ 3 | 4 | public boolean wordBreak(String s, Set wordDict) { 5 | boolean[] dp = new boolean[s.length() + 1]; 6 | dp[0] = true; 7 | for (int i = 1; i < dp.length; i++) 8 | for (int j = 0; j < i; j++) 9 | if (dp[j] && wordDict.contains(s.substring(j, i))) { 10 | dp[i] = true; 11 | break; 12 | } 13 | return dp[s.length()]; 14 | } 15 | 16 | 给一个字符串 such as: "GoogleFacebookMicrosoft", 由字母构成,然后给一个字典,把给定的字符按照字典进行切割,然后输出分割后的一个解答, 17 | 例如:dict=['Google', 'Facebook', 'Microsoft', 'GoogleFace', 'bookMicsoft'] 18 | 如果有多个解答,输出一个即可,对于这个例子显然有两个解答,"Google Facebook Microsoft", "GoogleFace bookMicrosoft"。随便输出一个就行 19 | 我回答,递归可以做,然后给出了答案,分析了复杂度O(n^m)。这里复杂度分析卡了一下,不过还好 20 | 21 | followup,有没有其他方法可以做?我说可以DP做,f[i] = True意味着0~i-1存在 matching,为了输出一个solution,用g[i+len(w)] = i记录结果,然后回溯方法可以输出一个答案。interviewer跑了个conner case比较满意。 22 | // http://www.1point3acres.com/bbs/forum.php?mod=redirect&goto=findpost&ptid=207049&pid=2597080&fromuid=96813 23 | 24 | public String wordBreak(String s, Set dict) { 25 | if (s.length() == 0 || dict.size() == 0) return true; 26 | int maxLength = getMaxLength(dict); 27 | boolean[] dp = new boolean[s.length() + 1];//dp[i]:whether 0 to i part of string can be segmented into words in dict 28 | int[] words = new int[s.length() + 1];//words[i]:index of the end of a dict's word s.substr(i,words[i]) 29 | dp[0] = true; 30 | words[0] = -1; 31 | for (int i = 1; i <= s.length(); i++) //O(n) * O(maxLength) 32 | for (int lastWordLength = 1; lastWordLength <= maxLength && lastWordLength <= i; lastWordLength++) //<= i !!! 33 | if (dp[i - lastWordLength] && dict.contains(s.substring(i - lastWordLength, i))) {//need add s.substring !!! 34 | dp[i] = true;//if string from 0 to i-lastWordLength is segmentable, and i-lastWordLength to i is in dict 35 | words[i - lastWordLength] = i;//record the index of breaking position 36 | break;//eg. 0 L E E T C O D E -> L(F),i++ -> E(F),LE(F),i++ -> E(F),EE(F),LEE(F),i++ -> .....,LEET(T) 37 | } // T F F F T F F F T 38 | //remember to check dp[s.length()] first !!! 39 | if (!dp[s.length()]) return ""; 40 | StringBuilder sb = new StringBuilder(s.substring(0, words[0])); 41 | int start = words[0]; 42 | while (start != s.length()) { 43 | sb.append(" " + s.substring(start, words[start])); 44 | start = words[start];//remember to update start !!! 45 | } 46 | return sb.toString(); 47 | } 48 | private int getMaxLength(Set dict) { 49 | int max = 0; 50 | for (String s : dict) 51 | max = Math.max(max, s.length()); 52 | return max; 53 | } 54 | 55 | 56 | 57 | ------------------------------------------ 58 | 140. Word Break II 59 | // https://leetcode.com/problems/word-break-ii/ 60 | 61 | Solution 1: DP + DFS 62 | Time: O(n * m) + O(n * # of solutions), 63 | //where n is the length of the input string, m is the length of the longest word in the dictionary. 64 | 65 | public List wordBreak(String s, List wordDict) { 66 | List[] startPos = new List[s.length() + 1]; // all valid start pos for each valid end pos 67 | startPos[0] = new ArrayList<>(); 68 | int maxLen = 0; 69 | for (String w : wordDict) 70 | maxLen = Math.max(maxLen, w.length()); 71 | for (int i = 1; i <= s.length(); i++) 72 | for (int j = i - 1; j >= Math.max(0, i - maxLen); j--) { 73 | if (startPos[j] == null) continue; 74 | String word = s.substring(j, i); 75 | if (wordDict.contains(word)) { 76 | if (startPos[i] == null) startPos[i] = new ArrayList<>(); 77 | startPos[i].add(j); 78 | } 79 | } 80 | List res = new ArrayList<>(); 81 | if (startPos[s.length()] == null) return res; 82 | dfs(res, "", s.length(), s, startPos); 83 | return res; 84 | } 85 | private void dfs(List res, String tmp, int end, String s, List[] startPos) { 86 | if (end == 0) { 87 | res.add(tmp.substring(1)); 88 | return; 89 | } 90 | for (Integer start : startPos[end]) { 91 | String w = s.substring(start, end); 92 | dfs(res, " " + w + tmp, start, s, startPos); 93 | } 94 | } 95 | 96 | 97 | Solution 2: DFS + memoization 98 | 99 | Map> map = new HashMap>(); 100 | public List wordBreak(String s, Set wordDict) { 101 | List res = new ArrayList(); 102 | if (s == null || s.length() == 0) return res; 103 | if (map.containsKey(s)) return map.get(s); 104 | if (wordDict.contains(s)) res.add(s); // important 105 | for (int i = 1 ; i < s.length() ; i++) { 106 | String t = s.substring(i); 107 | if (wordDict.contains(t)) { 108 | List temp = wordBreak(s.substring(0 , i) , wordDict); 109 | if (temp.size() != 0) 110 | for(int j = 0 ; j < temp.size() ; j++) 111 | res.add(temp.get(j) + " " + t); 112 | } 113 | } 114 | map.put(s , res); 115 | return res; 116 | } 117 | 118 | 119 | normal DFS -> 'TLE' 120 | Time: O(2 ^ n) //http://www.1point3acres.com/bbs/forum.php?mod=redirect&goto=findpost&ptid=117602&pid=1699371&fromuid=96813 121 | 122 | public List wordBreak(String s, List wordDict) { 123 | List res = new ArrayList<>(); 124 | dfs(res, new StringBuilder(), 0, s, wordDict); 125 | return res; 126 | } 127 | private void dfs(List res, StringBuilder sb, int start, String s, List wordDict) { 128 | if (start == s.length()) { 129 | res.add(sb.substring(1)); 130 | return; 131 | } 132 | for (int i = start; i < s.length(); i++) { 133 | int len = sb.length(); 134 | if (wordDict.contains(s.substring(start, i + 1))) 135 | dfs(res, sb.append(" ").append(s.substring(start, i + 1)), i + 1, s, wordDict); 136 | sb.setLength(len); 137 | } 138 | } 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /151. Reverse Words in a String.java: -------------------------------------------------------------------------------- 1 | 151. Reverse Words in a String 2 | 3 | Clarification: 4 | What constitutes a word? 5 | A sequence of non-space characters constitutes a word. 6 | Could the input string contain leading or trailing spaces? 7 | Yes. However, your reversed string should not contain leading or trailing spaces. 8 | How about multiple spaces between two words? 9 | Reduce them to a single space in the reversed string. 10 | 11 | 12 | Solution:split + 倒序遍历append 13 | 14 | public String reverseWords(String s) { 15 | String[] strs = s.split(" "); 16 | StringBuilder sb = new StringBuilder(); 17 | for (int i = strs.length - 1; i >= 0; i--) 18 | if (!strs[i].equals("")) 19 | sb.append(strs[i]).append(" "); 20 | return sb.length() == 0 ? "" : sb.substring(0, sb.length() - 1); 21 | } 22 | 23 | 此题不难,注意clarification里的细节,要去除头尾空格,单词中间多个空格reverse后只能有一个。 24 | 25 | 26 | 27 | 28 | 186. Reverse Words in a String II 29 | 30 | public void reverseWords(char[] s) { 31 | reverse(s, 0, s.length - 1); // reverse the whole sentense 32 | int start = 0; 33 | for (int i = 0; i < s.length; i++) // reverse each word 34 | if (s[i] == ' ') { 35 | reverse(s, start, i - 1); 36 | start = i + 1; 37 | } 38 | reverse(s, start, s.length - 1); // reverse the last word 39 | } 40 | private void reverse(char[] s, int i, int j) { 41 | while (i < j) { 42 | char tmp = s[i]; 43 | s[i++] = s[j]; 44 | s[j--] = tmp; 45 | } 46 | } -------------------------------------------------------------------------------- /152. Maximum Product Subarray.java: -------------------------------------------------------------------------------- 1 | 152. Maximum Product Subarray 2 | // https://leetcode.com/problems/maximum-product-subarray/ 3 | 4 | public int maxProduct(int A[], int n) { 5 | if (n == 0) return 0; 6 | int maxProduct = A[0], minProduct = A[0], maxRes = A[0]; 7 | for (int i = 1; i < n; i++) { 8 | if (A[i] >= 0) { 9 | maxProduct = max(maxProduct * A[i], A[i]); 10 | minProduct = min(minProduct * A[i], A[i]); 11 | } else { 12 | int temp = maxProduct; 13 | maxProduct = max(minProduct * A[i], A[i]); 14 | minProduct = min(temp * A[i], A[i]); 15 | } 16 | maxRes = max(maxRes, maxProduct); 17 | } 18 | return maxRes; 19 | } -------------------------------------------------------------------------------- /161. One Edit Distance.java: -------------------------------------------------------------------------------- 1 | 161. One Edit Distance 2 | // https://leetcode.com/problems/one-edit-distance/ 3 | 4 | 5 | Tests: 1.replace one char, 2.delete one char in s, 3.delete one char in t 6 | corner cases: "" (len = 0) 7 | 8 | public boolean isOneEditDistance(String s, String t) { 9 | int len = Math.min(s.length(), t.length()); 10 | for (int i = 0; i < len; i++) { 11 | if (s.charAt(i) != t.charAt(i)) { 12 | if (s.length() == t.length()) return s.substring(i + 1).equals(t.substring(i + 1)); // replace 13 | else if (s.length() < t.length()) return s.substring(i).equals(t.substring(i + 1)); // delete t 14 | else return s.substring(i + 1).equals(t.substring(i)); // delete s 15 | } 16 | } 17 | return Math.abs(s.length() - t.length()) == 1; // corner case: "" 18 | } 19 | 20 | 原题 但是不能用substring ====>>> 要一个字符一个字符比较 -------------------------------------------------------------------------------- /17. Letter Combinations of a Phone Number.java: -------------------------------------------------------------------------------- 1 | 17. Letter Combinations of a Phone Number 2 | 3 | Input:Digit string "23" 4 | Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 5 | 6 | 注意map取index时要 -‘0’ 7 | 8 | Time: O(3 ^ n) 9 | 10 | public List letterCombinations(String digits) { 11 | String[] map = new String[]{"0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; 12 | List res = new ArrayList<>(); 13 | if (digits.length() == 0) return res; // important! "" -> [] Not [""] 14 | dfs(res, "", map, digits, 0); 15 | return res; 16 | } 17 | private void dfs(List res, String tmp, String[] map, String digits, int start) { 18 | if (start == digits.length()) { 19 | res.add(tmp); 20 | return; 21 | } 22 | for (int i = 0; i < map[digits.charAt(start) - '0'].length(); i++) { // -'0' 23 | dfs(res, tmp + map[digits.charAt(start) - '0'].charAt(i), map, digits, start + 1); 24 | } 25 | } -------------------------------------------------------------------------------- /173. Binary Search Tree Iterator.java: -------------------------------------------------------------------------------- 1 | 173. Binary Search Tree Iterator 2 | 3 | public class BSTIterator { 4 | private Stack stack; 5 | public BSTIterator(TreeNode root) { 6 | stack = new Stack<>(); 7 | pushAll(root); 8 | } 9 | public boolean hasNext() { 10 | return !stack.isEmpty(); 11 | } 12 | public int next() { 13 | TreeNode node = stack.pop(); 14 | pushAll(node.right); 15 | return node.val; 16 | } 17 | private void pushAll(TreeNode node) { 18 | while (node != null) { 19 | stack.push(node); 20 | node = node.left; 21 | } 22 | } 23 | } 24 | ******变种****** 25 | 写个BST的in-order iterator,要写的function有 next() 和 all(), all() return所有剩下的。 26 | public class BSTIterator { 27 | private Stack stack; 28 | public BSTIterator(TreeNode root) { 29 | stack = new Stack<>(); 30 | pushAll(root); 31 | } 32 | private void pushAll(TreeNode node) { 33 | while (node != null) { 34 | stack.push(node); 35 | node = node.left; 36 | } 37 | } 38 | public boolean hasNext() { 39 | return !stack.isEmpty(); 40 | } 41 | public TreeNode next() { 42 | TreeNode node = stack.pop(); 43 | pushAll(node.right); 44 | return node; 45 | } 46 | public List all() { 47 | List res = new ArrayList<>(); 48 | while (hasNext()) 49 | res.add(next()); 50 | return res; 51 | } 52 | } 53 | 54 | ************Follow up****** 55 | 改成 preorder 和 postorder。 我全用的stack 56 | 57 | public List preorderTraversal(TreeNode root) { 58 | List res = new ArrayList<>(); 59 | if (root == null) return res; // corner check 60 | Stack stack = new Stack<>(); 61 | stack.push(root); 62 | while (!stack.empty()) { 63 | res.add(stack.pop().val); 64 | if (root.right != null) stack.push(root.right); 65 | if (root.left != null) stack.push(root.left); 66 | } 67 | return res; 68 | } 69 | 70 | public List inorderTraversal(TreeNode root) { 71 | List res = new ArrayList<>(); 72 | Stack stack = new Stack<>(); 73 | while (root != null || !stack.empty()) { 74 | while (root != null) { 75 | stack.push(root); 76 | root = root.left; 77 | } 78 | res.add(stack.pop().val); 79 | root = root.right; 80 | } 81 | return res; 82 | } 83 | 84 | public List postorderTraversal(TreeNode root) { 85 | List res = new ArrayList<>(); 86 | Stack stack = new Stack<>(); 87 | TreeNode prev = null; 88 | while (root != null || !stack.empty()) { 89 | if (root != null) { 90 | stack.push(root); 91 | root = root.left; 92 | } else { 93 | TreeNode tmp = stack.peek(); 94 | if (tmp.right != null && tmp.right != prev) 95 | root = tmp.right; 96 | else { 97 | stack.pop(); 98 | res.add(tmp.val); 99 | prev = tmp; 100 | } 101 | } 102 | } 103 | return res; 104 | } -------------------------------------------------------------------------------- /200. Number of Islands.java: -------------------------------------------------------------------------------- 1 | 200. Number of Islands 2 | // https://leetcode.com/problems/number-of-islands/ 3 | 4 | Solution 1: DFS 5 | Time: O(m * n) 6 | 7 | public int numIslands(char[][] grid) { 8 | if (grid.length == 0 || grid[0].length == 0) return 0; 9 | int m = grid.length, n = grid[0].length, res = 0; 10 | for (int i = 0; i < m; i++) 11 | for (int j = 0; j < n; j++) 12 | if (grid[i][j] == '1') { 13 | DFSMarking(grid, i, j); 14 | res++; 15 | } 16 | return res; 17 | } 18 | public void DFSMarking(char[][] grid, int i, int j) { 19 | if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') 20 | return; 21 | grid[i][j] = '0'; 22 | DFSMarking(grid, i + 1, j); 23 | DFSMarking(grid, i, j + 1); 24 | DFSMarking(grid, i, j - 1); 25 | DFSMarking(grid, i - 1, j); 26 | } 27 | 28 | Solution 2: BFS 29 | public int[][] dirs = new int[][]{{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; 30 | public int numIslands(char[][] grid) { 31 | if (grid.length == 0 || grid[0].length == 0) return 0; 32 | int m = grid.length, n = grid[0].length, res = 0; 33 | for (int i = 0; i < m; i++) 34 | for (int j = 0; j < n; j++) 35 | if (grid[i][j] == '1') { 36 | bfs(grid, i, j); 37 | res++; 38 | } 39 | return res; 40 | } 41 | private void bfs(char[][] grid, int i, int j) { 42 | Queue q = new LinkedList<>(); 43 | q.offer(new int[]{i, j}); 44 | while (!q.isEmpty()) { 45 | int[] pos = q.poll(); 46 | for (int[] d : dirs) { 47 | int x = pos[0] + d[0], y = pos[1] + d[1]; 48 | if (x < 0 || x >= grid.length || y < 0 || y >= grid[0].length || grid[x][y] != '1') 49 | continue; 50 | grid[x][y] = '0'; 51 | q.offer(new int[]{x, y}); 52 | } 53 | } 54 | } 55 | 56 | Solution 3: Union - Find 57 | 58 | public int numIslands(char[][] grid) { 59 | if (grid.length == 0 || grid[0].length == 0) return 0; 60 | int m = grid.length, n = grid[0].length; 61 | UnionFind uf = new UnionFind(grid, m, n); 62 | for (int i = 0; i < m; i++) 63 | for (int j = 0; j < n; j++) 64 | if (grid[i][j] == '1') { 65 | int p = i * n + j, q; 66 | if (i > 0 && grid[i - 1][j] == '1') { 67 | q = p - n; 68 | uf.union(p, q); 69 | } 70 | if (j > 0 && grid[i][j - 1] == '1') { 71 | q = p - 1; 72 | uf.union(p, q); 73 | } 74 | if (i < m - 1 && grid[i + 1][j] == '1') { 75 | q = p + n; 76 | uf.union(p, q); 77 | } 78 | if (j < n - 1 && grid[i][j + 1] == '1') { 79 | q = p + 1; 80 | uf.union(p, q); 81 | } 82 | } 83 | return uf.getCount(); 84 | } 85 | class UnionFind{ 86 | int[] lands; 87 | int count; 88 | public UnionFind(char[][] grid, int m, int n) { 89 | for (int i = 0; i < m; i++) 90 | for (int j = 0; j < n; j++) 91 | if (grid[i][j] == '1') count++; 92 | lands = new int[m * n]; 93 | for (int i = 0; i < m * n; i++) 94 | lands[i] = -1; 95 | } 96 | public boolean isConnected(int i, int j) { 97 | return find(i) == find(j); 98 | } 99 | public int find(int i) { 100 | if (lands[i] < 0) 101 | return i; 102 | else { //path compression 103 | lands[i] = find(lands[i]); 104 | return lands[i]; 105 | } 106 | } 107 | public void union(int i, int j) { 108 | int root1 = find(i), root2 = find(j); 109 | if (root1 == root2) return; 110 | if (lands[root1] > lands[root2]) { 111 | lands[root2] += lands[root1]; 112 | lands[root1] = root2; 113 | } else { 114 | lands[root1] += lands[root2]; 115 | lands[root2] = root1; 116 | } 117 | count--; 118 | } 119 | public int getCount() { 120 | return count; 121 | } 122 | } 123 | 124 | 1, 如果加上斜的也可以。dfs加四种情况 125 | 2, 不让改变原有的input,我就说那就建一个相同size的2d boolean array。grid复制给visit,改变visit,或者加参数boolean visited[][] 126 | 3, 转换为union find或者bfs,bfs解法:https://discuss.leetcode.com/topic/12230/c-bfs-solution-may-help-you 127 | 128 | 129 | 130 | 131 | 132 | ******变种1****** 133 | 求largest size of islands 134 | // dfs solution 135 | public int numIslands(char[][] grid) { 136 | if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) return 0; 137 | int m = grid.length, n = grid[0].length, max = 0; 138 | boolean[][] visited = new boolean[m][n];//O(1) space: directly modify the '1' to '2' to mark grid[i][j] visited 139 | for (int i = 0; i < m; i++) 140 | for (int j = 0; j < n; j++) 141 | if (grid[i][j] == '1' && !visited[i][j]) 142 | max = Math.max(max, dfs(grid, visited, m, n, i, j)); 143 | return max; 144 | } 145 | private int dfs(char[][] grid, boolean[][] visited, int m, int n, int i, int j) { 146 | if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] != '1' || visited[i][j]) return 0; // important! 147 | visited[i][j] = true; 148 | return 1 + dfs(grid, visited, m, n, i + 1, j) + dfs(grid, visited, m, n, i - 1, j) 149 | + dfs(grid, visited, m, n, i, j + 1) + dfs(grid, visited, m, n, i, j - 1); 150 | } 151 | 152 | // bfs solution 153 | 略 154 | 155 | 156 | *****变种***** 157 | 求perimeter of given island,注意想明白island的周长到底指什么 158 | 159 | // dfs solution 160 | public int numIslands(char[][] grid, int i, int j) { 161 | if (grid == null || grid.length == 0 || grid[0] == null || grid[0].length == 0) return 0; 162 | int m = grid.length, n = grid[0].length; 163 | if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] != '1') return 0; 164 | boolean[][] visited = new boolean[m][n];//O(1) space: directly modify the '1' to '2' to mark grid[i][j] visited 165 | return dfs(grid, visited, m, n, i, j); 166 | } 167 | private int dfs(char[][] grid, boolean[][] visited, int m, int n, int i, int j) { 168 | if (i < 0 || i >= m || j < 0 || j >= n || grid[i][j] != '1') 169 | return 1; // important 170 | if (visited[i][j]) return 0; 171 | visited[i][j] = true; 172 | return dfs(grid, visited, m, n, i + 1, j) + dfs(grid, visited, m, n, i - 1, j) + dfs(grid, visited, m, n, i, j + 1) + dfs(grid, visited, m, n, i, j - 1); 173 | } 174 | 175 | // bfs solution 176 | 略 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | -------------------------------------------------------------------------------- /206. Reverse Linked List.java: -------------------------------------------------------------------------------- 1 | 206. Reverse Linked List 2 | // https://leetcode.com/problems/reverse-linked-list/ 3 | 4 | Solution 1: iterative 5 | public ListNode reverseList(ListNode head) { 6 | ListNode newHead = null; 7 | while(head != null) { 8 | ListNode next = head.next; 9 | head.next = newHead; 10 | newHead = head; 11 | head = next; 12 | } 13 | return newHead; 14 | } 15 | 16 | Solution 2: recursive 17 | public ListNode reverseList(ListNode head) { 18 | return helper(head, null); 19 | } 20 | private ListNode helper(ListNode cur, ListNode newHead) { 21 | if (cur == null) return newHead; 22 | ListNode next = cur.next; 23 | cur.next = newHead; 24 | return helper(next, cur); 25 | } 26 | 27 | 28 | 变种: 29 | print linkedlist reversely, recursive (print linked list, no reverse) 30 | if cannot use recursion, cannot modify the linkedlist, we can use StringBuilder.reverse().toString() 31 | 32 | 1,递归: 33 | public void reverseList(ListNode head) { 34 | if (head == null) return; 35 | reverseList(head.next); 36 | System.out.print(head.val + " "); 37 | } 38 | 39 | 2,非递归: 40 | public void print(ListNode head){ 41 | Stack stack = new Stack<>(); 42 | while (head != null) { 43 | stack.push(head); 44 | head = head.next; 45 | } 46 | while (!stack.isEmpty()) 47 | System.out.println(stack.poll().val); 48 | } 49 | 50 | Follow Up: 51 | if we need to use O(logn) space ? we can use recursion to print the right part, and then the left part 52 | 53 | Solution: D & C 54 | O(nlogn) time, O(logn) space 55 | 56 | public void reverseList(ListNode head) { 57 | if (head == null) return; 58 | ListNode curr = head; 59 | int length = 0; 60 | while (curr != null) {//get the total length 61 | curr = curr.next; 62 | length++; 63 | } 64 | helper(head, length); 65 | } 66 | private void helper(ListNode head, int length) { 67 | if (length == 1) { 68 | System.out.print(head.val + " "); 69 | return;//remember to return !!! 70 | } 71 | ListNode curr = head; 72 | int count = 0; 73 | while (count < length / 2) { 74 | curr = curr.next; 75 | count++; 76 | } 77 | helper(curr, length - length / 2);//note that the right part has length - length / 2 nodes 78 | helper(head, length / 2); 79 | } 80 | 81 | -------------------------------------------------------------------------------- /211. Add and Search Word - Data structure design.java: -------------------------------------------------------------------------------- 1 | 211. Add and Search Word - Data structure design 2 | 3 | addWord("bad") 4 | addWord("dad") 5 | addWord("mad") 6 | search("pad") -> false 7 | search("bad") -> true 8 | search(".ad") -> true 9 | search("b..") -> true 10 | 11 | 12 | Time: add / search: O(wordLength) average, For search -> max O(26^n) 13 | Space: O(numOfTrieNode * 26) = O(numOfWords * wordLength * 26) 14 | 15 | public class WordDictionary { 16 | class TrieNode { 17 | boolean isWord; 18 | TrieNode[] children; 19 | public TrieNode() { 20 | children = new TrieNode[26]; 21 | } 22 | } 23 | TrieNode root; 24 | /** Initialize your data structure here. */ 25 | public WordDictionary() { 26 | root = new TrieNode(); 27 | } 28 | /** Adds a word into the data structure. */ 29 | public void addWord(String word) { 30 | TrieNode node = root; 31 | char[] chs = word.toCharArray(); 32 | for (int i = 0; i < chs.length; i++) { 33 | char c = chs[i]; 34 | if (node.children[c - 'a'] == null) 35 | node.children[c - 'a'] = new TrieNode(); 36 | node = node.children[c - 'a']; 37 | } 38 | node.isWord = true; 39 | } 40 | /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */ 41 | public boolean search(String word) { 42 | return dfs(word.toCharArray(), 0, root); 43 | } 44 | private boolean dfs(char[] word, int start, TrieNode root) { 45 | if (start == word.length) return root.isWord; 46 | char c = word[start]; 47 | if (c == '.') { 48 | for (int i = 0; i < 26; i++) 49 | if (root.children[i] != null && dfs(word, start + 1, root.children[i])) return true; 50 | } else { 51 | if (root.children[c - 'a'] != null) 52 | return dfs(word, start + 1, root.children[c - 'a']); 53 | } 54 | return false; 55 | } 56 | } 57 | 58 | *******************follow up****************** 59 | 如果模糊查询只有"...book"和“book...”这两种模式怎么处 , 60 | 回答,只要建 顺序 tire树,反序tire树,就可以 。 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /215. Kth Largest Element in an Array.java: -------------------------------------------------------------------------------- 1 | 215. Kth Largest Element in an Array 2 | // https://leetcode.com/problems/kth-largest-element-in-an-array/ 3 | 4 | Given [3,2,1,5,6,4] and k = 2, return 5. 5 | 先讨论 heap和 quick select的解法和复杂度 实现 quickselect的解法 6 | 7 | Solution 1: Quick Select 8 | 9 | Time: O(n) average, the problem is reduced to approximately half of its original size, giving the recursion T(n) = T(n/2) + O(n) 10 | O(n^2) worst case, the recursion may become T(n) = T(n - 1) + O(n) 11 | // In the average sense, the problem is reduced to approximately half of its original size, giving the recursion T(n) = T(n/2) + O(n) 12 | // in which O(n) is the time for partition. This recursion, once solved, gives T(n) = O(n) and thus we have a linear time solution. 13 | // Note that since we only need to consider one half of the array, the time complexity is O(n). 14 | // If we need to consider both the two halves of the array, like quicksort, then the recursion will be T(n) = 2T(n/2) + O(n) and the complexity will be O(nlogn). 15 | // Of course, O(n) is the average time complexity. In the worst case, the recursion may become T(n) = T(n - 1) + O(n) and the complexity will be O(n^2). 16 | 17 | public int findKthLargest(int[] nums, int k) { 18 | int left = 0, right = nums.length - 1; 19 | while (true) { // this problem guaranteed to have a valid answer 20 | int pos = partition(nums, left, right); 21 | if (pos == k - 1) return nums[pos]; 22 | else if (pos < k - 1) left = pos + 1; 23 | else right = pos - 1; 24 | } 25 | } 26 | private int partition(int[] nums, int left, int right) { 27 | shuffle(nums); 28 | int pivot = nums[left], idx = left; 29 | swap(nums, idx, right); 30 | for (int i = left; i < right; i++) 31 | if (nums[i] > pivot) swap(nums, i, idx++); 32 | swap(nums, idx, right); 33 | return idx; 34 | } 35 | private void swap(int[] nums, int i, int j) { 36 | int tmp = nums[i]; 37 | nums[i] = nums[j]; 38 | nums[j] = tmp; 39 | } 40 | private void shuffle(int a[]) { 41 | final Random random = new Random(); 42 | for(int ind = 1; ind < a.length; ind++) { 43 | final int r = random.nextInt(ind + 1); 44 | swap(a, ind, r); 45 | } 46 | } 47 | 48 | 49 | Solution 2: PQ 50 | 51 | Time: O(nlogk) 52 | 53 | public int findKthLargest(int[] nums, int k) { 54 | PriorityQueue pq = new PriorityQueue<>(); 55 | for (int n : nums) { 56 | pq.offer(n); 57 | if (pq.size() > k) pq.poll(); 58 | } 59 | return pq.peek(); 60 | } -------------------------------------------------------------------------------- /221. Maximal Square.java: -------------------------------------------------------------------------------- 1 | 221. Maximal Square 2 | 3 | Given a 2D binary matrix filled with 0s and 1s, find the largest square containing only 1s and return its area. 4 | For example, given the following matrix: 5 | 1 0 1 0 0 6 | 1 0 1 1 1 7 | 1 1 1 1 1 8 | 1 0 0 1 0 9 | Return 4. 10 | 11 | Solution: DP 12 | dp[i][j] = Math.min(Math.min(dp[i][j-1] , dp[i-1][j-1]), dp[i-1][j]) + 1; 13 | 14 | //mine 15 | public int maximalSquare(char[][] matrix) { 16 | if (matrix.length == 0) return 0; 17 | int m = matrix.length, n = matrix[0].length, max = 0; 18 | int[] prev = new int[n + 1]; 19 | for (int i = 0; i < m; i++) { 20 | int[] cur = new int[n + 1]; 21 | for (int j = 0; j < n; j++) 22 | if (matrix[i][j] == '1') { 23 | cur[j + 1] = Math.min(cur[j], Math.min(prev[j + 1], prev[j])) + 1; 24 | max = Math.max(max, cur[j + 1]); 25 | } 26 | prev = cur; 27 | } 28 | return max * max; 29 | } 30 | 31 | // https://leetcode.com/articles/maximal-square/ 32 | public int maximalSquare(char[][] matrix) { 33 | if (matrix.length == 0) return 0; 34 | int m = matrix.length, n = matrix[0].length; 35 | int max = 0; 36 | int[] dp = new int[n + 1]; 37 | for (int i = 0; i < m; i++) { 38 | int prev = 0; 39 | for (int j = 0; j < n; j++) { 40 | int tmp = dp[j + 1]; 41 | if (matrix[i][j] == '1') { 42 | dp[j + 1] = Math.min(dp[j], Math.min(dp[j + 1], prev)) + 1; 43 | max = Math.max(max, dp[j + 1]); 44 | } else dp[j + 1] = 0; // important!! 45 | prev = tmp; 46 | } 47 | } 48 | return max * max; 49 | } -------------------------------------------------------------------------------- /230. Kth Smallest Element in a BST.java: -------------------------------------------------------------------------------- 1 | 230. Kth Smallest Element in a BST 2 | 3 | 4 | 5 | private int res = 0, count; 6 | public int kthSmallest(TreeNode root, int k) { 7 | //recursive 8 | count = k; 9 | dfsInOrder(root); 10 | return res; 11 | } 12 | public void dfsInOrder(TreeNode root) { 13 | if (root.left != null) dfsInOrder(root.left); 14 | count--; 15 | if (count == 0) { 16 | res = root.val; 17 | return; 18 | } 19 | if (root.right != null) dfsInOrder(root.right); 20 | } 21 | 22 | 23 | 24 | //iterative 25 | public int kthSmallest(TreeNode root, int k) { 26 | Stack stack = new Stack<>(); 27 | while (root != null) { 28 | stack.push(root); 29 | root = root.left; 30 | } 31 | while (k > 0) { 32 | TreeNode tmp = stack.pop(); 33 | if (--k == 0) return tmp.val; 34 | tmp = tmp.right; 35 | while (tmp != null) { 36 | stack.push(tmp); 37 | tmp = tmp.left; 38 | } 39 | } 40 | return -1; 41 | } -------------------------------------------------------------------------------- /235. Lowest Common Ancestor of Binary Search Tree.java: -------------------------------------------------------------------------------- 1 | 235. Lowest Common Ancestor of Binary Search Tree 2 | 3 | (1) with parent pointer 4 | // https://www.careercup.com/question?id=56769 5 | // http://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=176715 6 | follow up是如果两个节点靠的很近怎么办,这样如果树的height太高,这样就需要把所有的ancestors都遍历一遍,我想了半天,不过最后还是想出来了, 7 | 只要边存边查就可以了,不用先全部遍历把所有ancestors都存到hashSet里,他说cool,然后就是问问题。(注意考虑一下如果有一个节点是Null,或者两个节点不在同一个tree里怎么办) 8 | 9 | Solution 1: Hashset ( Time: O(h), Space: O(h) ) 10 | public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 11 | Set ancestors = new HashSet<>(); 12 | while (p != null || q != null) { 13 | if (p != null) { 14 | if (!ancestors.add(p)) return p; 15 | p = p.parent; 16 | } 17 | if (q != null) { 18 | if (!ancestors.add(q)) return q; 19 | q = q.parent; 20 | } 21 | } 22 | return null; 23 | } 24 | 25 | Solution 2: depth ( Time: O(h), Space: O(1) ) 26 | public static TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { 27 | int h1 = getHeight(p), h2 = getHeight(q); 28 | if (h1 < h2) { 29 | int tmp = h1; 30 | h1 = h2; 31 | h2 = tmp; 32 | TreeNode t = p; 33 | p = q; 34 | q = t; 35 | } 36 | int deltaH = h1 - h2; 37 | while (deltaH-- > 0) 38 | p = p.parent; 39 | while (p != null && q != null) { 40 | if (p == q) return p; 41 | p = p.parent; 42 | q = q.parent; 43 | } 44 | return null; 45 | } 46 | private static int getHeight(TreeNode node) { 47 | int height = 0; 48 | while (node != null) { 49 | node = node.parent; 50 | height++; 51 | } 52 | return height; 53 | } 54 | 55 | (2) without parent pointer 56 | Solution 1: iteration 57 | 58 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 59 | while ((root.val - p.val) * (root.val - q.val) > 0) 60 | root = p.val < root.val ? root.left : root.right; 61 | return root; 62 | } 63 | 64 | Solution 2: recursion 65 | 66 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 67 | if ((root.val - p.val) * (root.val - q.val) <= 0) return root; 68 | else if (p.val < root.val) 69 | return lowestCommonAncestor(root.left, p, q); 70 | else 71 | return lowestCommonAncestor(root.right, p, q); 72 | } 73 | 74 | 75 | ------------------------------------------- 76 | 236. Lowest Common Ancestor of Binary Tree 77 | 78 | // Recursively expands the meaning of the function. If the current (sub)tree contains both p and q, then the function result 79 | // is their LCA. If only one of them is in that subtree, then the result is that one of them. If neither are in that subtree, 80 | // the result is null. 81 | 82 | public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 83 | if (root == null || root == p || root == q) return root; 84 | TreeNode left = lowestCommonAncestor(root.left, p, q); 85 | TreeNode right = lowestCommonAncestor(root.right, p, q); 86 | return left == null ? right : right == null ? left : root; 87 | } 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /253. Meeting Rooms II.java: -------------------------------------------------------------------------------- 1 | 253. Meeting Rooms II 2 | // https://leetcode.com/problems/meeting-rooms-ii/ 3 | Given [[0, 30],[5, 10],[15, 20]], 4 | return 2. 5 | 6 | Solution 1: greedy 7 | public int minMeetingRooms(Interval[] intervals) { 8 | int[] start = new int[intervals.length]; 9 | int[] end = new int[intervals.length]; 10 | for (int i = 0; i < intervals.length; i++) { 11 | start[i] = intervals[i].start; 12 | end[i] = intervals[i].end; 13 | } 14 | Arrays.sort(start); 15 | Arrays.sort(end); 16 | int endIdx = 0, res = 0; 17 | for (int i = 0; i < start.length; i++) { 18 | if (start[i] < end[endIdx]) res++; 19 | else endIdx++; 20 | } 21 | return res; 22 | } 23 | 24 | Solution 2: PQ 25 | public int minMeetingRooms(Interval[] intervals) { 26 | if (intervals == null || intervals.length == 0) return 0; 27 | Arrays.sort(intervals, new Comparator(){ 28 | public int compare(Interval i1, Interval i2) { 29 | return i1.start - i2.start; 30 | } 31 | }); 32 | PriorityQueue pq = new PriorityQueue<>(new Comparator(){ 33 | public int compare(Interval i1, Interval i2) { 34 | return i1.end - i2.end; 35 | } 36 | }); 37 | pq.offer(intervals[0]); 38 | for (int i = 1; i < intervals.length; i++) { 39 | Interval interval = pq.poll(); 40 | if (intervals[i].start >= interval.end) 41 | interval.end = intervals[i].end; 42 | else 43 | pq.offer(intervals[i]); 44 | pq.offer(interval); 45 | } 46 | return pq.size(); 47 | } 48 | 49 | ********变种1******** 50 | Return the exact time that has max num of room used (any valid time) 51 | 和原题基本一样,只需想明白最后一次overlapStart - overlapEnd之间的任意时间都使用了最大数目的房间。所以you can return any time between overlapStart and overlapEnd 52 | 53 | public int minMeetingRooms(Interval[] intervals) { 54 | if (intervals == null || intervals.length == 0) return 0; 55 | Arrays.sort(intervals, new Comparator(){ 56 | public int compare(Interval a, Interval b) { 57 | return a.start - b.start; 58 | } 59 | }); 60 | Queue heap = new PriorityQueue<>();//no need to store interval, we can just store the end time 61 | heap.offer(intervals[0].end); 62 | int overlapStart = -1, overlapEnd = -1; 63 | for (int i = 1; i < intervals.length; i++) { 64 | if (intervals[i].start >= heap.peek()) {//if can use room that ends earliest,poll that end time,add curr end time 65 | heap.poll(); 66 | } else { 67 | overlapStart = intervals[i].start; 68 | overlapEnd = Math.min(heap.peek(), intervals[i].end);//should be min of these two 69 | } 70 | heap.offer(intervals[i].end);//add curr end time 71 | } 72 | return overlapStart;//you can return any time between overlapStart and overlapEnd 73 | } 74 | 75 | ******变种2****** 76 | Return the num of room used / employees of each non-overlapping time range(you can design you own output) 77 | eg. [2004, 2007], [2005, 2007], [2006, 2008] -> 2004-2005: 1; 2005-2006: 2; 2006-2007: 3; 2007-2008: 1; 78 | 79 | 如果the format of intervals are "March, 2014" etc, first convert it to "201403" by "2014" + "03"(hashmap:March->03) 80 | // http://www.1point3acres.com/bbs/thread-109379-2-1.html 81 | 82 | O(nlogn) time, O(n) space 83 | 84 | 问(1,2),(2,4),(3,5)该输出["1-2:1","2-3:1","3-4:2","4-5:1"]还是["1-3:1","3-4:2","4-5:1"] 85 | 下面的代码是输出["1-2:1","2-3:1","3-4:2","4-5:1"]的。 86 | 87 | public class TimeSlot { 88 | int time; 89 | boolean isStart; 90 | public TimeSlot(int t, boolean i) { 91 | time = t; 92 | isStart = i; 93 | } 94 | } 95 | public List meetingRooms(Interval[] intervals) { 96 | List res = new ArrayList<>(); 97 | if (intervals == null || intervals.length == 0) return res; 98 | List times = new ArrayList<>(); 99 | for (Interval i : intervals) { 100 | times.add(new TimeSlot(i.start, true)); 101 | times.add(new TimeSlot(i.end, false)); 102 | } 103 | Collections.sort(times, new Comparator(){ 104 | public int compare(TimeSlot a, TimeSlot b) { 105 | return a.time - b.time; 106 | } 107 | }); 108 | int count = 1, startIdx = 0;//it's the index of begin time, not the time itself 109 | for (int i = 1; i < times.size(); i++) { 110 | if (times.get(i).time != times.get(i - 1).time) { 111 | res.add(times.get(startIdx).time + "-" + times.get(i).time + ": " + count); 112 | startIdx = i; 113 | } 114 | if (times.get(i).isStart) count++; 115 | else count--; 116 | } 117 | return res; 118 | } 119 | 120 | 121 | ******变种2****** 122 | print each room usage time intervals: Room 1:[2, 6],[7, 9]; Room 2:[3, 5],[8, 10]; etc. 123 | 返回每个房间 所有的会议 的开始时间和结束时间。 124 | 125 | 把所有的interval排序一下,建立一个priorityqueue> 按照List最后一个interval 的end来排序,如果新来的interval起点 126 | 比最早结束的interval终点早,或者priorityqueue为空,create 一个新的List, 否则, poll priorityqueue。 把新的interval 加进去就好了。 127 | one pass。 方法来自机经,非自创 128 | // http://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=222745&extra=page%3D1%26filter%3Dsortid%26sortid%3D311%26searchoption%5B3090%5D%5Bvalue%5D%3D2%26searchoption%5B3090%5D%5Btype%5D%3Dradio%26searchoption%5B3046%5D%5Bvalue%5D%3D2%26searchoption%5B3046%5D%5Btype%5D%3Dradio%26sortid%3D311 129 | O(nlogn) time, O(n) space 130 | 131 | public void MeetingRooms(Interval[] intervals) { 132 | if (intervals == null || intervals.length == 0) return; 133 | Arrays.sort(intervals, new Comparator(){ 134 | public int compare(Interval a, Interval b) { 135 | return a.start - b.start; 136 | } 137 | }); 138 | Queue> rooms = new PriorityQueue<>(1, new Comparator>(){ 139 | public int compare(List a, List b) { 140 | return a.getLast().end - b.getLast().end; 141 | } 142 | }); 143 | for (Interval i : intervals) { 144 | List room = null; 145 | if (rooms.isEmpty() || i.start < rooms.peek().getLast().end) //if need new room(no rooms/all curr rooms overlap) 146 | room = new LinkedList<>(); 147 | else room = queue.poll();//else use the previous room that ends earliest (no overlap with curr meeting) 148 | room.add(i);//add curr meeting into the room, which is at the back of the linkedlist 149 | rooms.offer(room); 150 | } 151 | while (!rooms.isEmpty()) { 152 | List room = rooms.poll(); 153 | //you can maintain a roomNum and System.out.print("Room " + roomNum + ":"); 154 | for (Interval i : room) //print each meeting in a same room 155 | System.out.print("[" + i.start + "-" i.end + "],"); 156 | System.out.println(); 157 | } 158 | } 159 | 160 | ******变种3****** 161 | Return the time ranges of free time between startTime and endTime (time ranges that have no meetings) 162 | 163 | O(nlogn) time, O(1) space 164 | 165 | public List minMeetingRooms(Interval[] intervals, int start, int end) { 166 | List res = new ArrayList<>(); 167 | if (intervals == null || intervals.length == 0) return res; 168 | Collections.sort(intervals, new Comparator(){ 169 | public int compare(Interval a, Interval b) { 170 | return a.start - b.start; 171 | } 172 | }); 173 | int begin = start;//the beginTime of freeTime (end of last meeting) 174 | for (Interval i : intervals) { 175 | if (begin >= end) break; 176 | if (i.start > begin) 177 | res.add(begin + "-" + Math.min(i.start, end));//if the i.start exceeds end, we pick end to be the boundary 178 | begin = Math.max(begin, i.end); 179 | } 180 | return res; 181 | } 182 | 183 | 184 | 185 | 186 | 252. Meeting Rooms 187 | // https://leetcode.com/problems/meeting-rooms/ 188 | 189 | public boolean canAttendMeetings(Interval[] intervals) { 190 | if (intervals == null) return false; 191 | Arrays.sort(intervals, new Comparator() {//sort by start time also works fine. 192 | public int compare(Interval i1, Interval i2) { 193 | return i1.end - i2.end; 194 | } 195 | }); 196 | for (int i = 1; i< intervals.length; i++) 197 | if (intervals[i].start < intervals[i - 1].end) return false; 198 | return true; 199 | } 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | -------------------------------------------------------------------------------- /257. Binary Tree Paths.java: -------------------------------------------------------------------------------- 1 | 257. Binary Tree Paths 2 | 3 | Time: O(nlogn) 4 | 5 | public List binaryTreePaths(TreeNode root) { 6 | List res = new ArrayList<>(); 7 | dfs(res, root, ""); 8 | return res; 9 | } 10 | private void dfs(List res, TreeNode root, String tmp) { 11 | if (root == null) return; 12 | if (root.left == null && root.right == null) 13 | res.add(tmp + root.val); 14 | dfs(res, root.left, tmp + root.val + "->"); 15 | dfs(res, root.right, tmp + root.val + "->"); 16 | } 17 | 18 | 考虑print path 19 | 1 如果所有的node在一条线上,时间复杂度。O(n^2) 20 | 2 full binary tree 时间复杂度。O(nlogn) 21 | 3 优化时间复杂度:StringBuilder 22 | 23 | // iterative (dfs pre-order) 两个stack: 一个treenode,一个stringbuilder 24 | public List binaryTreePaths(TreeNode root) { 25 | List res = new ArrayList<>(); 26 | if (root == null) return res; 27 | Stack stack = new Stack<>(); 28 | Stack paths = new Stack<>(); 29 | stack.push(root); 30 | paths.push(new StringBuilder(root.val + ""));//remember to add + "" !!! 31 | while (!stack.empty()) { 32 | TreeNode node = stack.pop(); 33 | StringBuilder path = paths.pop(); 34 | if (node.left == null && node.right == null) 35 | res.add(path.toString()); 36 | if (node.right != null) { 37 | stack.push(node.right); 38 | StringBuilder newPath = new StringBuilder(path); 39 | paths.push(newPath.append("->").append(node.right.val)); 40 | } 41 | if (node.left != null) { 42 | stack.push(node.left); 43 | StringBuilder newPath = new StringBuilder(path); 44 | paths.push(newPath.append("->").append(node.left.val)); 45 | } 46 | } 47 | return res; 48 | } 49 | 50 | 51 | *****Follow Up1**** 52 | If we cannot use dfs(which is easy for printing paths) 53 | then use bfs, use hashmap to store parent-to-children paths 54 | 55 | public void binaryTreePaths(TreeNode root) { 56 | List res = new ArrayList<>(); 57 | if (root == null) return res; 58 | HashMap map = new HashMap<>(); // (node, parent node) 59 | Queue queue = new LinkedList<>(); 60 | queue.offer(root); 61 | map.put(root, null); 62 | while (!queue.isEmpty()) { 63 | TreeNode curr = queue.poll(); 64 | if (curr.left == null && curr.right == null) { 65 | String path = getPath(map, curr);//if you only want to print paths, we can use recursion here 66 | res.add(path); 67 | } 68 | if (curr.left != null) { 69 | map.put(curr.left, curr); 70 | queue.offer(curr.left); 71 | } 72 | if (curr.right != null) { 73 | map.put(curr.right, curr); 74 | queue.offer(curr.right); 75 | } 76 | } 77 | return res; 78 | } 79 | private String getPath(HashMap map, TreeNode node) { 80 | StringBuilder sb = new StringBuilder(); 81 | while (node != null) {//from leaf to root 82 | sb.append(node.val + ">-"); 83 | node = map.get(node); 84 | } 85 | return sb.reverse().substring(2); 86 | } 87 | 88 | 89 | // iterative (bfs), use queue to store ArrayList, which is the path 90 | public List binaryTreePaths(TreeNode root) { 91 | List res = new ArrayList<>(); 92 | if (root == null) return res; 93 | Queue> queue = new LinkedList<>(); 94 | queue.offer(new ArrayList<>(Arrays.asList(root))); 95 | while (!queue.isEmpty()) { 96 | ArrayList path = queue.poll(); 97 | TreeNode curr = path.get(path.size() - 1); 98 | if (curr.left == null && curr.right == null) { 99 | StringBuilder sb = new StringBuilder(); 100 | for (TreeNode node : path) 101 | sb.append(node.val + "->"); 102 | sb.setLength(sb.length() - 2);//it's void type !!! 103 | res.add(sb.toString()); 104 | continue; 105 | } 106 | if (curr.left != null) { 107 | ArrayList newPath = new ArrayList<>(path); 108 | newPath.add(curr.left); 109 | queue.offer(newPath); 110 | } 111 | if (curr.right != null) { 112 | ArrayList newPath = new ArrayList<>(path); 113 | newPath.add(curr.right); 114 | queue.offer(newPath); 115 | } 116 | } 117 | return res; 118 | } 119 | 120 | 121 | 122 | ******变种***** 123 | 比如有一个 root to leaf path 是 1 2 5 2,target 是2,那么这个 path 就应该打印成 1 1 2 5 1 2 5 2。每次遇到 2 就把前面的路径重新 append 一下: 1 (1 2) 5 (1 2 5 2). 124 | 125 | public List binaryTreePaths(TreeNode root,int target) { 126 | List res = new ArrayList<>(); 127 | if (root == null) return res; 128 | helper(res, root, "", "", target); 129 | return res; 130 | } 131 | public void helper(List res, TreeNode root, String s, String target_s, int target){ 132 | if (root == null) return; 133 | if (root.left == null && root.right == null) 134 | if (root.val == target) 135 | res.add(target_s + s + root.val); 136 | else res.add(target_s + root.val); 137 | if (root.val == target) { 138 | helper(res, root.left, s + root.val + "->", target_s + s + root.val + "->", target); 139 | helper(res, root.right, s + root.val + "->", target_s + s + root.val + "->", target); 140 | } else { 141 | helper(res, root.left, s + root.val + "->", target_s + root.val + "->", target); 142 | helper(res, root.right, s + root.val + "->", target_s + root.val + "->", target); 143 | } 144 | } 145 | 146 | 147 | 148 | -------------------------------------------------------------------------------- /261. Graph Valid Tree.java: -------------------------------------------------------------------------------- 1 | 261. Graph Valid Tree 2 | // https://leetcode.com/problems/graph-valid-tree/ 3 | 4 | Given n = 5 and edges = [[0, 1], [0, 2], [0, 3], [1, 4]], return true. 5 | Given n = 5 and edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], return false. 6 | 7 | 8 | Test: 9 | //1. corner case: n == 1 && edges.length == 0. eg. n = 1, [], it's true 10 | //2. edges.length != n - 1 --> a valid n-node tree should have n - 1 edges 11 | //3. initialize roots[i] = -1 12 | //4. find method --> cycle exists ? return false : union them 13 | 14 | 15 | Solution 1: Union - Find (no need to create disjoint set) 16 | Time: O(V*E), find: O(V) 17 | 18 | public boolean validTree(int n, int[][] edges) { 19 | // if (edges.length == 0 && n == 1) return true; 20 | if (edges.length != n - 1) return false; 21 | int[] vertices = new int[n]; 22 | Arrays.fill(vertices, -1); // use -1, clean code 23 | for (int[] e : edges) { 24 | int i = find(vertices, e[0]); 25 | int j = find(vertices, e[1]); 26 | if (i == j) return false; // cycle detected, false 27 | vertices[j] = i; // connect edge 28 | } 29 | return true; 30 | } 31 | private int find(int[] nums, int i) { 32 | if (nums[i] == -1) return i; // here also use -1 33 | return find(nums, nums[i]); 34 | } 35 | 36 | 37 | 38 | Solution 2: DFS in graph 39 | [YouTube: Cycle Dection in Undirected Graph] // https://www.youtube.com/watch?v=n_t0a_8H8VY 40 | 41 | public boolean validTree(int n, int[][] edges) { 42 | List> adjList = new ArrayList<>(); 43 | //if (edges.length == 0 && n == 1) return true; 44 | if (edges.length != n - 1) return false; 45 | for (int i = 0; i < n; i++) 46 | adjList.add(i, new LinkedList<>()); 47 | for (int[] edge : edges) { 48 | adjList.get(edge[0]).add(edge[1]); 49 | adjList.get(edge[1]).add(edge[0]); 50 | } 51 | boolean[] visited = new boolean[n]; 52 | if (hasCycle(adjList, visited, 0, -1)) return false; // here use 0 as graph source 53 | for (int i = 0; i < n; i++) // but 0 may not be in 'adjList', so should check if all vertices are visited, e.x.[[1,2],[2,3],[1,3]] 54 | if (!visited[i]) return false; 55 | return true; 56 | } 57 | public boolean hasCycle(List> adjList, boolean[] visited, int i, int pre) { 58 | visited[i] = true; 59 | for (int v : adjList.get(i)) 60 | if (v != pre && visited[v] || !visited[v] && hasCycle(adjList, visited, v, i)) return true; 61 | return false; 62 | } 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /273. Integer to English Words.java: -------------------------------------------------------------------------------- 1 | 273. Integer to English Words 2 | // https://leetcode.com/problems/integer-to-english-words/?tab=Description 3 | LC273把数字转换成英语。然后还是要 run test cases 4 | 123 -> "One Hundred Twenty Three" 5 | 12345 -> "Twelve Thousand Three Hundred Forty Five" 6 | 1234567 -> "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven" 7 | 8 | Hint: 9 | Did you see a pattern in dividing the number into chunk of words? For example, 123 and 123000. 10 | Group the number by thousands (3 digits). You can write a helper function that takes a number less than 1000 and convert just that chunk to words. 11 | There are many edge cases. What are some good test cases? Does your code work with input such as 0? Or 1000010? (middle chunk is zero and should not be printed out) 12 | 13 | Test: 14 | 0 15 | 1000 16 | 1000010 17 | 18 | 注意: i++的位置;最后结果要trim(). 19 | 20 | private final String[] LESS_THAN_20 = {"", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; 21 | private final String[] TENS = {"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; 22 | private final String[] THOUSANDS = {"", "Thousand", "Million", "Billion"}; 23 | public String numberToWords(int num) { 24 | if (num == 0) return "Zero"; 25 | int i = 0; 26 | String res = ""; 27 | while (num > 0) { 28 | if (num % 1000 != 0) // 3 digits a group 29 | res = helper(num % 1000) +THOUSANDS[i] + " " + res; 30 | num /= 1000; 31 | i++; // cannot put into THOUSANDS[i++] !!! e.x. 1000 32 | } 33 | return res.trim(); // important 34 | } 35 | private String helper(int num) { 36 | if (num == 0) return ""; // necessary! 50868 37 | else if (num < 20) return LESS_THAN_20[num] + " "; // 1 - 19 38 | else if (num < 100) return TENS[num / 10] + " " + helper(num % 10); // 20,30,40,50,60,70,80,90 39 | else return LESS_THAN_20[num / 100] + " Hundred " + helper(num % 100); // > 100 40 | } -------------------------------------------------------------------------------- /277. Find the Celebrity.java: -------------------------------------------------------------------------------- 1 | 277. Find the Celebrity 2 | 3 | public int findCelebrity(int n) { 4 | int candidate = 0; 5 | for (int i = 1; i < n; i++) 6 | if (knows(candidate, i)) candidate = i; 7 | for (int i = 0; i < n; i++) { 8 | if (i < candidate && (!knows(i, candidate) || knows(candidate, i))) return -1; 9 | if (i > candidate && !knows(i, candidate)) return -1; 10 | } 11 | return candidate; 12 | } 13 | 14 | // The first loop is to find the candidate as the author explains. In detail, suppose the candidate after the first for loop is person k, 15 | // it means 0 to k-1 cannot be the celebrity, because they know a previous or current candidate. Also, 16 | // since k knows no one between k+1 and n-1, k+1 to n-1 can not be the celebrity either. Therefore, 17 | // k is the only possible celebrity, if there exists one. 18 | 19 | 20 | -------------------------------------------------------------------------------- /278. First Bad Version.java: -------------------------------------------------------------------------------- 1 | 278. First Bad Version 2 | // https://leetcode.com/problems/first-bad-version/ 3 | 4 | public int firstBadVersion(int n) { 5 | int left = 1, right = n; 6 | while (left < right) { 7 | int mid = left + (right - left) / 2; 8 | if (isBadVersion(mid)) right = mid; 9 | else left = mid + 1; 10 | } 11 | return left; 12 | } -------------------------------------------------------------------------------- /28. Implement strStr().java: -------------------------------------------------------------------------------- 1 | 28. Implement strStr() 2 | 3 | Time: O(mn) 4 | 5 | public int strStr(String haystack, String needle) { 6 | // TLE 7 | // if (needle.length() == 0) return 0; 8 | // for (int i = 0; i <= haystack.length(); i++) { 9 | // int j = 0; 10 | // for (; j < needle.length(); j++) 11 | // if (i + j >= haystack.length() || needle.charAt(j) != haystack.charAt(i + j)) break; 12 | // if (j == needle.length()) return i; 13 | // } 14 | // return -1; 15 | // optimized 16 | if (needle.length() == 0) return 0; // edge case: "",""=>0 "a",""=>0 17 | for (int i = 0; i <= haystack.length() - needle.length(); i++) { // possible starting points 18 | for (int j = 0; j < needle.length() && needle.charAt(j) == haystack.charAt(i + j); j++) 19 | if (j == needle.length() - 1) return i; 20 | } 21 | return -1; 22 | } 23 | 24 | 25 | *******变种******* 26 | find the first index in haystack that starts with an anagram of needle 27 | assume only lowercase letters in strings 28 | 29 | O(mn) time, O(m) space 30 | 31 | public int strStr(String haystack, String needle) { 32 | if (needle.length() == 0) return 0; 33 | int m = haystack.length(), n = needle.length(); 34 | HashMap map = new HashMap<>(); 35 | for (int i = 0; i <= m - n; i++) {//we use m - n to reduce time; should be <=, not < ! 36 | String key = createKey(haystack, i, n); 37 | if (!map.containsKey(key)) 38 | map.put(key, i); 39 | } 40 | String target = createKey(needle, 0, n); 41 | return map.containsKey(target) ? map.get(target) : -1; 42 | } 43 | 44 | private String createKey(String s, int start, int length) { 45 | int[] count = new int[26]; //see this as O(1) space 46 | for (int i = 0; i < length; i++) //O(n) time 47 | count[s.charAt(start + i) - 'a']++; 48 | String key = ""; 49 | for (int j = 0; j < count.length; j++) //see this as O(1) time 50 | if (count[j] != 0) 51 | key += String.valueOf(count[j]) + String.valueOf((char)('a' + j)); 52 | return key; 53 | } 54 | 55 | //http://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=130978&fromuid=109727 -------------------------------------------------------------------------------- /282. Expression Add Operators.java: -------------------------------------------------------------------------------- 1 | 282. Expression Add Operators 2 | 此题简单版见最后 3 | // https://leetcode.com/problems/expression-add-operators/ 4 | "123", 6 -> ["1+2+3", "1*2*3"] 5 | "232", 8 -> ["2*3+2", "2+3*2"] 6 | "105", 5 -> ["1*0+5","10-5"] 7 | "00", 0 -> ["0+0", "0-0", "0*0"] 8 | "3456237490", 9191 -> [] 9 | 10 | Test: 11 | - edge cases: 12 | // overflow: we use a long type once it is larger than Integer.MAX_VALUE or minimum, we get over it. 13 | // 0 sequence: because we cannot have numbers with multiple digits started with zero, we have to deal with it too. 14 | "105", 5 -> ["1*0+5","10-5"] //0 sequence 15 | "00", 0 -> ["0+0", "0-0", "0*0"] //0 sequence 16 | "3456237490", 9191 -> [] // no answer 17 | "232", 8 -> ["2*3+2", "2+3*2"] 18 | // a little trick is that we should save the value that is to be multiplied in the next recursion. 19 | // for example, if you have a sequence of 12345 and you have proceeded to 1 + 2 + 3, now your eval is 6 right? 20 | // If you want to add a * between 3 and 4, you would take 3 as the digit to be multiplied, so you want to take it out from the existing eval. 21 | // You have 1 + 2 + 3 * 4 and the eval now is (1 + 2 + 3) - 3 + (3 * 4). 22 | 23 | Time: O(n * 4^n) ??? 24 | // Each digit have 4 situations(+,-,*,none)下面分析不对 25 | // T(n) = 3 * T(n-1) + 3 * T(n-2) + 3 * T(n-3) + ... + 3 *T(1); 26 | // T(n-1) = 3 * T(n-2) + 3 * T(n-3) + ... 3 * T(1); 27 | // Thus T(n) = 4T(n-1); 28 | 29 | public List addOperators(String num, int target) { 30 | List res = new ArrayList<>(); 31 | StringBuilder sb = new StringBuilder(); 32 | dfs(res, sb, num, target, 0, 0, 0); 33 | return res; 34 | } 35 | private void dfs(List res, StringBuilder sb, String nums, int target, int start, long eval, long mult) { 36 | if (start == nums.length()) { 37 | if (eval == target) res.add(sb.toString()); 38 | return; 39 | } 40 | // dfs call on all numbers starting at position 'start' 41 | for (int i = start; i < nums.length(); i++) { 42 | if (nums.charAt(start) == '0' && i != start) break; // '0' cannot be leading number, so stop further dfs 43 | long cur = Long.valueOf(nums.substring(start, i + 1)); 44 | int len = sb.length(); 45 | if (start == 0) 46 | dfs(res, sb.append(cur), nums, target, i + 1, eval + cur, cur); 47 | else { 48 | dfs(res, sb.append("+").append(cur), nums, target, i + 1, eval + cur, cur); 49 | sb.setLength(len); 50 | dfs(res, sb.append("-").append(cur), nums, target, i + 1, eval - cur, -cur); 51 | sb.setLength(len); 52 | dfs(res, sb.append("*").append(cur), nums, target, i + 1, eval - mult + mult * cur, mult * cur); 53 | } 54 | sb.setLength(len); 55 | } 56 | } 57 | 58 | [StringBuilder V.S. String] 59 | // http://blog.csdn.net/shfqbluestone/article/details/34188325 60 | 61 | 62 | 63 | 64 | *******简单版******* 65 | 给1个string “123456789”, 进行arithmetic oepration combination. 66 | 如: 123 + 456 + 78 -9 是1种组合, -1 + 2 -3 +4 -5 - 67 + 89 也是1种(只加 + 或 -), 打印出所有结果等于 100 的组合 67 | 68 | Test: 69 | "1234567" -> ["1+2+34+56+7", "1+23+4+5+67"] 70 | 71 | public List addOperators(String num, int target) { 72 | List res = new ArrayList<>(); 73 | dfs(res, "", num, target, 0, 0); 74 | return res; 75 | } 76 | private void dfs(List res, String tmp, String nums, int target, int start, long eval) { 77 | if (start == nums.length()) { 78 | if (eval == target) res.add(tmp); 79 | return; 80 | } 81 | // dfs call on all numbers starting at position 'start' 82 | for (int i = start; i < nums.length(); i++) { 83 | if (nums.charAt(start) == '0' && i != start) break; // '0' cannot be leading number, so stop further dfs 84 | long cur = Long.valueOf(nums.substring(start, i + 1)); 85 | if (start == 0) 86 | dfs(res, tmp + cur, nums, target, i + 1, eval + cur); 87 | else { 88 | dfs(res, tmp + "+" + cur, nums, target, i + 1, eval + cur); 89 | dfs(res, tmp + "-" + cur, nums, target, i + 1, eval - cur); 90 | } 91 | } 92 | } 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /283. Move Zeroes.java: -------------------------------------------------------------------------------- 1 | 283. Move Zeroes 2 | 3 | public void moveZeroes(int[] nums) { 4 | if (nums == null || nums.length == 0) return; 5 | int idx = 0; 6 | for (int num: nums) 7 | if (num != 0) nums[idx++] = num; 8 | while (idx < nums.length) 9 | nums[idx++] = 0; 10 | } 11 | 12 | 代码只需要返回最后有效数组的长度,有效长度之外的数字是什么无所谓,原先input里面的数字不一定要保持原来的相对顺序。 13 | 1.不用保持非零元素的相对顺序 14 | 2.不用把0移到右边 15 | 思路:把右边的非0元素移动到左边的0元素位置。这样就可以minimize writes. 16 | 17 | public int moveZeroesWithMinWrites(int[] nums) { 18 | int left = 0, right = nums.length - 1; 19 | while (left < right) { 20 | while (left < right && nums[left] != 0) left++; 21 | while (left < right && nums[right] == 0) right--; 22 | if (left < right) nums[left++] = nums[right--]; 23 | } 24 | return left; 25 | } 26 | 27 | 28 | -------------------------------------------------------------------------------- /285. Inorder Successor in BST.java: -------------------------------------------------------------------------------- 1 | 285. Inorder Successor in BST 2 | 写完之后,面试官不太满意,觉得如果树很大的话,时间复杂度太高,然后交流了一下,发现面试官想要的答案是,TreeNode可以带parent指针的,输入只有一个TreeNode,没有root。所以一定要和面试官好好交流,写代码之前问清楚输入输出是什么才行。。 3 | Write an algorithm to find the "next" node (i.e., in-order successor) of a given node in a binary search tree. You may assume that each node has a link to its parent. 4 | 5 | TreeNode没有parent引用: 6 | 7 | 下面两种解法本质一样,都是充分利用BST的性质。 8 | Solution 1: iteration (4ms) 9 | // The idea is to compare root's value with p's value if root is not null, and consider the following two cases: 10 | // root.val > p.val. In this case, root can be a possible answer, so we store the root node first and call it res. However, we don't know if there is anymore node on root's left that is larger than p.val. So we move root to its left and check again. 11 | // root.val <= p.val. In this case, root cannot be p's inorder successor, neither can root's left child. So we only need to consider root's right child, thus we move root to its right and check again. 12 | // We continuously move root until exhausted. To this point, we only need to return the res in case 1.' 13 | 14 | public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { 15 | TreeNode res = null; 16 | while (root != null) { 17 | if (root.val > p.val) { 18 | res = root; 19 | root = root.left; 20 | } else root = root.right; 21 | } 22 | return res; 23 | } 24 | 25 | Solution 2: recursion (5ms) 26 | 上面那种方法也可以写成递归形式,写法也比较简洁,但是需要把思路理清,当根节点值小于等于p节点值,说明p的后继节点一定在右子树中,所以对右子节点递归调用此函数,如果根节点值大于p节点值,那么有可能根节点就是p的后继节点,或者左子树中的某个节点是p的后继节点,所以先对左子节点递归调用此函数,如果返回空,说明根节点是后继节点,返回即可,如果不为空,则将那个节点返回。这种解法可以用作模板,求BST的inorder successor和predecessor 27 | 28 | 29 | 模板 [BST InOrder Successor / Predecessor] 30 | // successor 31 | public TreeNode inorderSuccessor(TreeNode root, TreeNode p) { 32 | if (root == null) return null; 33 | if (root.val > p.val) { 34 | TreeNode left = inorderSuccessor(root.left, p); 35 | return left == null ? root : left; 36 | } else return inorderSuccessor(root.right, p); 37 | } 38 | 39 | // predecessor 40 | public TreeNode inorderPredecessor(TreeNode root, TreeNode p) { 41 | if (root == null) return null; 42 | if (root.val < p.val) { 43 | TreeNode right = inorderSuccessor(root.right, p); 44 | return right == null ? root : right; 45 | } else return inorderPredecessor(root.left, p); 46 | } 47 | 48 | 49 | 2. TreeNode有parent引用: 50 | 51 | Pseudocode 52 | if n has a right subtree 53 | return leftmost child of right subtree 54 | else 55 | while n is a right child of n.parent 56 | n = n.parent // go northwest till end 57 | return n.parent // return 1st northeast node 58 | 59 | public TreeNode inOrderSuccessor(TreeNode n) { 60 | if (n == null) return null; 61 | if (n.right != null) 62 | return leftMostChild(n.right); 63 | else { 64 | TreeNode cur = n, p = n.parent; 65 | while (p != null && p.left != cur) { 66 | cur = p; 67 | p = p.parent; 68 | } 69 | return p; 70 | } 71 | } 72 | private TreeNode leftMostChild(TreeNode node) { 73 | while (node.left != null) 74 | node = node.left; 75 | return node; 76 | } 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /29. Divide Two Integers.java: -------------------------------------------------------------------------------- 1 | 29. Divide Two Integers 2 | // https://leetcode.com/problems/divide-two-integers/ 3 | 4 | Suppose we want to divide 15 by 3, so 15 is dividend and 3 is divisor. Well, division simply requires us to find how many times we can subtract the divisor from the the dividend without making the dividend negative. 5 | We subtract 3 from 15 and we get 12, which is positive. Then, we shift 3 to the left by 1 bit and we get 6. 6 | Subtracting 6 from 15 still gives a positive result. Well, we shift again and get 12. 7 | We subtract 12 from 15 and it is still positive. We shift again, obtaining 24 and we know we can at most subtract 12. 8 | Well, since 12 is obtained by shifting 3 to left twice, we know it is 4 times of 3. How do we obtain this 4? 9 | Well, we start from 1 and shift it to left twice at the same time. We add 4 to an answer (initialized to be 0). 10 | In fact, the above process is like 15 = 3 * 4 + 3. We now get part of the quotient (4), with a remainder 3. 11 | Then we repeat the above process again. We subtract divisor = 3 from the remaining dividend = 3 and obtain 0. 12 | We know we are done. No shift happens, so we simply add 1 << 0 to the answer. 13 | 14 | Test: 15 | divisor = 0; // overflow 16 | dividend = INT_MIN and divisor = -1 (because abs(INT_MIN) = INT_MAX + 1) // overflow 17 | 18 | Solution 1 (without multiply or division): Bit Manipulation 19 | Time: O((logn)^2) 20 | // The outer loop reduces n by at least half each iteration. So It has O(log N) iterations. 21 | // The inner loop has at most log N iterations. So the overall complexity is O((logN)^2) 22 | n 23 | public int divide(int dividend, int divisor) { 24 | if (divisor == 0 || dividend == Integer.MIN_VALUE && divisor == -1) 25 | return Integer.MAX_VALUE; 26 | int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1; 27 | long dvd = Math.abs((long) dividend); 28 | long dvs = Math.abs((long) divisor); 29 | int res = 0; 30 | while (dvd >= dvs) { 31 | long tmp = dvs, multiple = 1; 32 | while (dvd >= (tmp << 1)) { 33 | tmp <<= 1; 34 | multiple <<= 1; 35 | } 36 | dvd -= tmp; 37 | res += multiple; 38 | } 39 | return sign == 1 ? res : -res; 40 | } 41 | 42 | 注意,此题所有用long的地方都是必须的!! 43 | 1.long dvd = Math.abs((long) dividend); // 里面(long) dividend是为了防止 -2147483648 取绝对值overflow变成0 44 | 2.long tmp = dvs, multiple = 1; // 这个long和上面表达式最左边的long都是为了防止移位overflow,如 2147483647 << 1 变成 -2147483648,-2147483648再<<1就变成0,从而造成死循环 45 | 46 | 47 | 48 | 49 | Solution 2 (with multiply): Binary Search 50 | Time: O(logn) 51 | 52 | public int divide(int dividend, int divisor) { 53 | if (divisor == 0 || dividend == Integer.MIN_VALUE && divisor == -1) 54 | return Integer.MAX_VALUE; 55 | int sign = ((dividend < 0) ^ (divisor < 0)) ? -1 : 1; 56 | long dvd = Math.abs((long) dividend); 57 | long dvs = Math.abs((long) divisor); 58 | long l = 1, r = dvd; 59 | while (l < r) { 60 | long mid = l + (r - l) / 2 + 1; 61 | if (mid * dvs <= dvd) l = mid; 62 | else r = mid - 1; 63 | } 64 | return sign == 1 ? (int) l : (int) -l; 65 | } 66 | 67 | 68 | Solution 3: 不用bit Manipulation,只用加减法做 69 | public int divison(int num, int deno){ 70 | if (deno == 0 || (deno == -1 && num == Integer.MIN_VALUE)) return Integer.MAX_VALUE; 71 | int sign = ((n < 0) ^ (d < 0)) ? -1 : 1; 72 | long n = Math.abs((long) num), d = Math.abs((long) deno); 73 | int res = 0; 74 | while (n >= d){ 75 | n -= d; 76 | res++; 77 | } 78 | return res * sign; 79 | } 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /295. Find Median from Data Stream.java: -------------------------------------------------------------------------------- 1 | 295. Find Median from Data Stream 2 | // https://leetcode.com/problems/find-median-from-data-stream/ 3 | addNum(1) 4 | addNum(2) 5 | findMedian() -> 1.5 6 | addNum(3) 7 | findMedian() -> 2 8 | 9 | 10 | public class MedianFinder { 11 | PriorityQueue minHeap; // larger part 12 | PriorityQueue maxHeap; // smaller part 13 | 14 | public MedianFinder() { 15 | minHeap = new PriorityQueue<>(); 16 | maxHeap = new PriorityQueue<>(new Comparator(){ 17 | public int compare(Integer i1, Integer i2) { 18 | return i2 - i1; 19 | } 20 | }); 21 | } 22 | // Adds a number into the data structure. 23 | public void addNum(int num) { 24 | minHeap.offer(num); 25 | maxHeap.offer(minHeap.poll()); 26 | if (minHeap.size() < maxHeap.size()) 27 | minHeap.offer(maxHeap.poll()); 28 | } 29 | // Returns the median of current data stream 30 | public double findMedian() { 31 | return minHeap.size() > maxHeap.size() ? minHeap.peek() : (maxHeap.peek() + minHeap.peek()) / 2.0; 32 | } 33 | } -------------------------------------------------------------------------------- /297. Serialize and Deserialize Binary Tree.java: -------------------------------------------------------------------------------- 1 | 297. Serialize and Deserialize Binary Tree 2 | 3 | // Encodes a tree to a single string. 4 | public String serialize(TreeNode root) { 5 | StringBuilder sb = new StringBuilder(); 6 | buildString(root, sb); 7 | return sb.toString(); 8 | } 9 | public void buildString(TreeNode root, StringBuilder sb) { 10 | if (root == null) sb.append("#").append(" "); 11 | else { 12 | sb.append(root.val).append(" "); 13 | buildString(root.left, sb); 14 | buildString(root.right, sb); 15 | } 16 | } 17 | // Decodes your encoded data to tree. 18 | public TreeNode deserialize(String data) { 19 | Queue q = new LinkedList<>(); 20 | q.addAll(Arrays.asList(data.split(" "))); 21 | return buildTree(q); 22 | } 23 | public TreeNode buildTree(Queue q) { 24 | String s = q.remove(); 25 | if (s.equals("#")) return null; 26 | TreeNode root = new TreeNode(Integer.valueOf(s)); 27 | root.left = buildTree(q); 28 | root.right = buildTree(q); 29 | return root; 30 | } -------------------------------------------------------------------------------- /300. Longest Increasing Subsequence.java: -------------------------------------------------------------------------------- 1 | 300. Longest Increasing Subsequence 2 | // https://leetcode.com/problems/longest-increasing-subsequence/ 3 | Given [10, 9, 2, 5, 3, 7, 101, 18], 4 | 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. 5 | Your algorithm should run in O(n2) complexity. 6 | Follow up: Could you improve it to O(n log n) time complexity? 7 | 8 | Solution 1: DP 9 | Time: O(n^2) 10 | 11 | 注意,是返回max不是返回数组最后一个,所以中间要维护这个max变量 12 | 13 | public int lengthOfLIS(int[] nums) { 14 | int[] dp = new int[nums.length]; 15 | Arrays.fill(dp, 1); 16 | int max = 1; 17 | for (int i = 1; i < nums.length; i++) 18 | for (int j = 0; j < i; j++) 19 | if (nums[j] < nums[i] && dp[j] + 1 > dp[i]) { 20 | dp[i] = dp[j] + 1; 21 | max = Math.max(max, dp[i]); 22 | } 23 | return max; 24 | } 25 | 26 | 27 | 28 | Solution 2: DP with Binary Search 29 | // The idea is that as you iterate the sequence, you keep track of the minimum value a subsequence of given length might end with, 30 | // for all so far possible subsequence lengths. So dp[i] is the minimum value a subsequence of length i+1 might end with. 31 | // Having this info, for each new number we iterate to, we can determine the longest subsequence where it can be appended using binary search. 32 | // The final answer is the length of the longest subsequence we found so far. 33 | Time: O(nlogn) 34 | 35 | public int lengthOfLIS(int[] nums) { 36 | int[] dp = new int[nums.length]; 37 | int len = 0; 38 | for (int n : nums) { 39 | int i = Arrays.binarySearch(dp, 0, len, n); 40 | if (i < 0) i = - (i + 1); 41 | dp[i] = n; 42 | if (i == len) len++; 43 | } 44 | return len; 45 | } 46 | // Arrays.binarySearch() returns ( - insertion_index - 1) in cases where the element was not found in the array. -------------------------------------------------------------------------------- /301. Remove Invalid Parentheses.java: -------------------------------------------------------------------------------- 1 | 301. Remove Invalid Parentheses 2 | 常考简单版,见最后 3 | // https://leetcode.com/problems/remove-invalid-parentheses/ 4 | "()())()" -> ["()()()", "(())()"] 5 | "(a)())()" -> ["(a)()()", "(a())()"] 6 | ")(" -> [""] 7 | 8 | Solution 1: DFS 9 | // To make the prefix valid, we need to remove a ‘)’. The problem is: which one? The answer is any one in the prefix. 10 | // However, if we remove any one, we will generate duplicates, e.x. s = ()). Thus, we noly remove 1st ) in a series of concecutive )s. 11 | // After the removal, the prefix is then valid. We then call the function recursively to solve the rest of the string. 12 | // However, we need to keep another information: the last removal position. If we do not have this position, we will generate duplicates. 13 | // For this, we keep tracking the last removal position and only remove ‘)’ after that. 14 | // Now one may ask. What about ‘(‘? What if s = ‘(()(()’ in which we need remove ‘(‘? The answer is: do the same from right to left. 15 | // However a cleverer idea is: reverse the string and reuse the code! 16 | Time: O(nk), k: # of recursion calls 17 | Run: e.x."()())()" 18 | // "()())()" -> "(())()" -> ")())((" 19 | // -> "()()()" -> ")()()(" 20 | // res = ["(())()", "()()()"] 21 | Test: "", // empty 22 | ")(", // -> "" 23 | "()())()", // normal 24 | "(a)())()" // contain non-parenthesis char 25 | 26 | public List removeInvalidParentheses(String s) { 27 | List res = new ArrayList<>(); 28 | dfs(res, s, new char[]{'(', ')'}, 0, 0); 29 | return res; 30 | } 31 | private void dfs(List res, String s, char[] p, int iStart, int jStart) { 32 | // find 1st invalid p[1] 33 | int stack = 0, i; 34 | for (i = iStart; i < s.length(); i++) { 35 | if (s.charAt(i) == p[0]) stack++; 36 | if (s.charAt(i) == p[1]) stack--; 37 | // remove each (not consecutive) p[1] from jStart to i to make valid 38 | if (stack < 0) { 39 | for (int j = jStart; j <= i; j++) // <= 40 | if (s.charAt(j) == p[1] && (j == jStart || s.charAt(j - 1) != p[1])) { 41 | String r = s.substring(0, j) + s.substring(j + 1); 42 | dfs(res, r, p, i, j); 43 | } 44 | return; // important!! 45 | } 46 | } 47 | // stack >= 0 : try reverse s and re-do DFS; if already reversed, then add to res 48 | String reverse = new StringBuilder(s).reverse().toString(); 49 | if (p[0] == '(') 50 | dfs(res, reverse, new char[]{')', '('}, 0, 0); // important: 0, 0 51 | else 52 | res.add(reverse); 53 | } 54 | 55 | Solution 2: BFS -> guarantee the number of parentheses that need to be removed is minimal 56 | // With the input string s, we generate all possible states by removing one ( or ), check if they are valid, 57 | // if found valid ones on the current level, put them to res and we are done, otherwise add them to a queue and carry on to the next level 58 | Time: T(n) = n x C(n, n) + (n-1) x C(n, n-1) + ... + 1 x C(n, 1) = n x 2^(n-1). 59 | // In BFS we handle the states level by level, in the worst case, we need to handle all the levels, 60 | // we can analyze the time complexity level by level and add them up to get the final complexity. 61 | // On the first level, there's only one string which is the input string s, let's say the length of it is n, to check whether it's valid, 62 | // we need O(n) time. On the second level, we remove one ( or ) from the first level, so there are C(n, n-1) new strings, 63 | // each of them has n-1 characters, and for each string, we need to check whether it's valid or not, thus the total time complexity 64 | // on this level is (n-1) x C(n, n-1). Come to the third level, total time complexity is (n-2) x C(n, n-2), so on and so forth... 65 | Run: e.x. "(a)())()" 66 | // q = ["(a)())()"] 67 | // ["a)())()", "(a())()", "(a))()", "(a)()()", "(a)()))", "(a)())("] 68 | // visited = ["(a)())()", "a)())()", "(a())()", "(a))()", "(a)()()", "(a)()))", "(a)())("] 69 | // res = ["(a())()", "(a)()()"] 70 | 71 | 72 | public List removeInvalidParentheses(String s) { 73 | List res = new ArrayList<>(); 74 | if (s == null) return res; 75 | Queue q = new LinkedList<>(); 76 | Set visited = new HashSet<>(); // avoid duplicate results 77 | q.offer(s); 78 | visited.add(s); 79 | boolean foundValid = false; 80 | while (!q.isEmpty()) { 81 | String t = q.poll(); 82 | if (isValid(t)) { 83 | res.add(t); 84 | foundValid = true; 85 | } 86 | // found valid, no need to remove anymore, just iterative the rest of q and add to res when necessary 87 | if (foundValid) continue; 88 | for (int i = 0; i < t.length(); i++) { 89 | if(t.charAt(i) != '(' && t.charAt(i) != ')') continue; 90 | String r = t.substring(0, i) + t.substring(i + 1); 91 | if (visited.contains(r)) continue; 92 | visited.add(r); 93 | q.offer(r); 94 | } 95 | } 96 | return res; 97 | } 98 | // 记住此法=>检测括号是否匹配(仅限只含一种括号时,多种括号还是要用真正的stack) 99 | private boolean isValid(String s) { 100 | int count = 0; // stack variable 101 | for (int i = 0; i < s.length(); i++) { 102 | if (s.charAt(i) == '(') count++; 103 | if (s.charAt(i) == ')' && count-- = 0) return false; 104 | } 105 | return count == 0; 106 | } 107 | 108 | 109 | 110 | ********变种******** 111 | 简单版:只输出第一个valid的 112 | 113 | Time: O(n), 2 pass 114 | // 思路:按照判断isValid的思路,只要遇到stack<0就remove,完了之后reverse再来一次。 115 | public String removeInvalidParentheses(String s) { 116 | String r = remove(s, new char[]{'(', ')'}); 117 | String tmp = remove(new StringBuilder(r).reverse().toString(), new char[]{')', '('}); 118 | return new StringBuilder(tmp).reverse().toString(); 119 | } 120 | private String remove(String s, char[] p) { 121 | int stack = 0; 122 | for (int i = 0; i < s.length(); i++) { 123 | if (s.charAt(i) == p[0]) stack++; 124 | if (s.charAt(i) == p[1]) stack--; 125 | if (stack < 0) { 126 | s = s.substring(0, i) + s.substring(i + 1); 127 | i--; 128 | stack = 0; 129 | } 130 | } 131 | return s; 132 | } 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /314. Binary Tree Vertical Order Traversal.java: -------------------------------------------------------------------------------- 1 | 314. Binary Tree Vertical Order Traversal 2 | 3 | class TreeNodeWithCol { 4 | TreeNode treeNode; 5 | int col; 6 | public TreeNodeWithCol(TreeNode node, int col) { 7 | this.treeNode = node; 8 | this.col = col; 9 | } 10 | } 11 | public List> verticalOrder(TreeNode root) { 12 | List> res = new ArrayList<>(); 13 | if (root == null) return res; 14 | Map> map = new HashMap<>(); 15 | Queue bfs = new ArrayDeque<>(); 16 | bfs.add(new TreeNodeWithCol(root, 0)); 17 | int max = 0, min = 0; 18 | while (!bfs.isEmpty()) { 19 | TreeNodeWithCol node = bfs.poll(); 20 | int col = node.col; 21 | if (!map.containsKey(col)) map.put(col, new ArrayList<>()); 22 | map.get(col).add(node.treeNode.val); 23 | if (node.treeNode.left != null) { 24 | bfs.offer(new TreeNodeWithCol(node.treeNode.left, col - 1)); 25 | min = Math.min(min, col - 1); 26 | } 27 | if (node.treeNode.right != null) { 28 | bfs.offer(new TreeNodeWithCol(node.treeNode.right, col + 1)); 29 | max = Math.max(max, col + 1); 30 | } 31 | } 32 | for (int i = min; i <= max; i++) 33 | res.add(map.get(i)); 34 | return res; 35 | } 36 | 37 | //If you wanna avoid using hashmap cuz of key conflicts,you can use doubly-linked list,each node stores a Arraylist of vals, 38 | //then replace Queue cols with Queue cols,each time we poll,we first add it to curr node's arraylist, 39 | //put non-null left node to a new left list(if curr.prev == head), 40 | //put non-null right node to a new right list(if curr.next == tail), 41 | //finally iterate all lists from head to tail -------------------------------------------------------------------------------- /33. Search in Rotated Sorted Array.java: -------------------------------------------------------------------------------- 1 | 33. Search in Rotated Sorted Array 2 | 3 | public int search(int[] nums, int target) { 4 | int left = 0, right = nums.length - 1; 5 | while (left < right) { // find min idx, when left == right return left 6 | int mid = left + (right - left) / 2; 7 | if (nums[mid] > nums[right]) 8 | left = mid + 1; 9 | else right = mid; 10 | } 11 | if (target == nums[left]) return left; // performance improved 12 | int rotate = left; 13 | left = 0; 14 | right = nums.length - 1; 15 | while (left <= right) { // = return 16 | int mid = left + (right - left) / 2; 17 | int newMid = (mid + rotate) % nums.length; 18 | if (target < nums[newMid]) right = mid - 1; 19 | else if (target > nums[newMid]) left = mid + 1; 20 | else return newMid; 21 | } 22 | return -1; 23 | } 24 | 25 | public int search(int[] nums, int target) { 26 | int left = 0, right = nums.length - 1; 27 | while (left <= right) { // must find right idx within this loop : = 28 | int mid = (left + right) / 2; 29 | if (nums[mid] == target) return mid; 30 | else if (nums[mid] < nums[right]) 31 | if (nums[mid] < target && nums[right] >= target) 32 | left = mid + 1; 33 | else right = mid - 1; 34 | else 35 | if (nums[left] <= target && target < nums[mid]) 36 | right = mid - 1; 37 | else left = mid + 1; 38 | } 39 | return -1; 40 | } -------------------------------------------------------------------------------- /334. Increasing Triplet Subsequence.java: -------------------------------------------------------------------------------- 1 | 334. Increasing Triplet Subsequence 2 | // https://leetcode.com/problems/increasing-triplet-subsequence/ 3 | 4 | Given [1, 2, 3, 4, 5], 5 | return true. 6 | Given [5, 4, 3, 2, 1], 7 | return false. 8 | 9 | 问怎么test code,要求考虑corner cases。 10 | 11 | 12 | public boolean increasingTriplet(int[] nums) { 13 | int min = Integer.MAX_VALUE, secondMin = Integer.MAX_VALUE; 14 | for(int num : nums){ 15 | if(num <= min) min = num; // important 16 | else if(num <= secondMin) secondMin = num;// important 17 | else return true; 18 | } 19 | return false; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /340. Longest Substring with At Most K Distinct Cha.java: -------------------------------------------------------------------------------- 1 | 340. Longest Substring with At Most K Distinct Characters 2 | // https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/ 3 | Given s = “eceba” and k = 2, 4 | return "ece". 5 | 6 | public int lengthOfLongestSubstringKDistinct(String s, int k) { 7 | int start = 0, end = 0, len = 0, max = 0; 8 | int[] count = new int[128]; 9 | while (end < s.length()) { 10 | if (count[s.charAt(end++)]++ == 0) len++; 11 | while (len > k) 12 | if (count[s.charAt(start++)]-- == 1) len--; 13 | max = Math.max(max, end - start); 14 | } 15 | return max; 16 | } 17 | 18 | 19 | ********变种******* 20 | 返回string 21 | 22 | public String longestSubstringKDistinct(String s, int k) { 23 | String res = ""; 24 | int start = 0, end = 0, len = 0, max = 0; 25 | int[] count = new int[128]; 26 | while (end < s.length()) { 27 | if (count[s.charAt(end++)]++ == 0) len++; 28 | while (len > k) 29 | if (count[s.charAt(start++)]-- == 1) len--; 30 | if (end - start > max) { 31 | res = s.substring(start, end); 32 | max = end - start; 33 | } 34 | } 35 | return res; 36 | } 37 | -------------------------------------------------------------------------------- /377. Combination Sum IV.java: -------------------------------------------------------------------------------- 1 | 9377. Combination Sum IV 2 | 3 | 比如[1,2,3] 4例子,当我们在计算dp[3]的时候,3可以拆分为1+x,而x即为x=dp[3-1]=dp[2],3也可以拆分为2+x,此时x为x=dp[3-2]=dp[1], 4 | 3同样可以拆为3+x,此时x为x=dp[3-3]=dp[0],我们把所有的情况加起来就是组成3的所有情况了。 5 | 6 | Run: 7 | [1,2,3] target = 4 8 | dp[0] = 1, 9 | dp[1] = 1, 10 | dp[2] = 1 + 1 = 2, 11 | dp[3] = 1 + 1 + 2 = 4, 12 | dp[4] = 1 + 2 + 4 = 7 (we have no 4 in nums, so dp[4] = 1 + 2 + 4 = 7, not 1 + 1 + 2 + 4 = 8) 13 | 14 | // we know that target is the sum of numbers in the array. Imagine we only need one more number to reach target, 15 | // this number can be any one in the array, right? So the # of combinations of target, comb[target] = sum(comb[target - nums[i]]), 16 | // where 0 <= i < nums.length, and target >= nums[i]. 17 | // In the example given, we can actually find the # of combinations of 4 with the # of combinations of 3(4 - 1), 2(4- 2) and 1(4 - 3). 18 | // As a result, comb[4] = comb[4-1] + comb[4-2] + comb[4-3] = comb[3] + comb[2] + comb[1]. 19 | 20 | public int combinationSum4(int[] nums, int target) { 21 | if (nums.length == 0) return 0; // important since dp[0] = 1 22 | int[] dp = new int[target + 1]; 23 | dp[0] = 1; 24 | Arrays.sort(nums); 25 | // if target is much larger than num of nums, we can sort nums and break the inner for loop if j > i 26 | for (int i = 1; i <= target; i++) { 27 | for (int j = 0; j < nums.length && nums[j] <= i; j++) // notice: nums[j] <= i 28 | dp[i] += dp[i - nums[j]]; 29 | } 30 | return dp[target]; 31 | } 32 | 33 | *****Follow Up***** 34 | 35 | What if negative numbers are allowed in the given array? 36 | Then adding a num to the combination is not guaranteed to be increasing, which means I can add a huge bounch of negative nums 37 | and add a huge bounch of positive nums to achieve a target sum. 38 | eg.target=0:[-1,1],[-1,-1,1,1],[-1,-1,-1,1,1,1]... 39 | 40 | How does it change the problem? 41 | We will have lots of lots of possible combinations, even infinity. 42 | 43 | What limitation we need to add to the question to allow negative numbers? 44 | For example, each negative num can only be used once, etc. 45 | 46 | 47 | 48 | ' '''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' 49 | 50 | 40. Combination Sum II 51 | 52 | public List> combinationSum2(int[] nums, int target) { 53 | List> res = new ArrayList<>(); 54 | Arrays.sort(nums); 55 | dfs(res, new ArrayList<>(), nums, target, 0); 56 | return res; 57 | } 58 | private void dfs(List> res, List tmp, int[] nums, int sum, int start) { 59 | if (sum < 0) return; 60 | if (sum == 0) { 61 | res.add(new ArrayList<>(tmp)); 62 | return; 63 | } 64 | for (int i = start; i < nums.length; i++) { 65 | if (i > start && nums[i] == nums[i - 1]) continue; 66 | tmp.add(nums[i]); 67 | dfs(res, tmp, nums, sum - nums[i], i + 1); 68 | tmp.remove(tmp.size() - 1); 69 | } 70 | } 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /38. Count and Say.java: -------------------------------------------------------------------------------- 1 | 38. Count and Say 2 | // https://leetcode.com/problems/count-and-say 3 | The count-and-say sequence is the sequence of integers beginning as follows: 1, 11, 21, 1211, 111221, ... 4 | 1 is read off as "one 1" or 11. 5 | 11 is read off as "two 1s" or 21. 6 | 21 is read off as "one 2, then one 1" or 1211. 7 | Given an integer n, generate the nth sequence. 8 | 9 | 10 | public String countAndSay(int n) { 11 | String res = "1"; 12 | for (int i = 0; i < n - 1; i++) // total (n - 1) iterations 13 | res = generateCountAndSay(res); 14 | return res; 15 | } 16 | private String generateCountAndSay(String s) { 17 | StringBuilder sb = new StringBuilder(); 18 | char[] chs = s.toCharArray(); 19 | for (int i = 0; i < chs.length; i++) { 20 | int count = 1; 21 | while (i < chs.length - 1 && chs[i] == chs[i + 1]) { 22 | count++; 23 | i++; 24 | } 25 | sb.append(count).append(chs[i]); 26 | } 27 | return sb.toString(); 28 | } -------------------------------------------------------------------------------- /380. Insert Delete GetRandom O(1).java: -------------------------------------------------------------------------------- 1 | 380. Insert Delete GetRandom O(1) 2 | 3 | public class RandomizedSet { 4 | Map map; 5 | List nums; 6 | Random random; 7 | 8 | /** Initialize your data structure here. */ 9 | public RandomizedSet() { 10 | nums = new ArrayList<>(); 11 | map = new HashMap<>(); 12 | random = new Random(); 13 | } 14 | 15 | /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ 16 | public boolean insert(int val) { 17 | if (map.containsKey(val)) return false; 18 | map.put(val, nums.size()); 19 | nums.add(val); 20 | return true; 21 | } 22 | 23 | /** Removes a value from the set. Returns true if the set contained the specified element. */ 24 | public boolean remove(int val) { 25 | if (!map.containsKey(val)) return false; 26 | int pos = map.get(val); 27 | if (pos < map.size() - 1) { 28 | map.put(nums.get(nums.size() - 1), pos); 29 | nums.set(pos, nums.get(nums.size() - 1)); 30 | } 31 | map.remove(val); 32 | nums.remove(nums.size() - 1); 33 | return true; 34 | } 35 | 36 | /** Get a random element from the set. */ 37 | public int getRandom() { 38 | return nums.get(random.nextInt(nums.size())); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /394. Decode String.java: -------------------------------------------------------------------------------- 1 | 394. Decode String 2 | // https://leetcode.com/problems/decode-string/ 3 | 4 | s = "3[a]2[bc]", return "aaabcbc". 5 | s = "3[a2[c]]", return "accaccacc". 6 | s = "2[abc]3[cd]ef", return "abcabccdcdcdef". 7 | 8 | // digit: push into count stack, 9 | // letter: update res, 10 | // [: push res to res stack, 11 | // ]: pop out of res stack and append res count times 12 | 13 | public String decodeString(String s) { 14 | StringBuilder res = new StringBuilder(); 15 | Stack resStack = new Stack<>(); 16 | Stack countStack = new Stack<>(); 17 | int i = 0; 18 | while (i < s.length()) { 19 | char c = s.charAt(i); 20 | if (Character.isDigit(c)) { 21 | int count = 0; 22 | while (Character.isDigit(s.charAt(i))) 23 | count = count * 10 + s.charAt(i++) - '0'; 24 | countStack.push(count); 25 | } else if (c == '[') { 26 | resStack.push(new StringBuilder(res)); // important 27 | res.setLength(0); 28 | i++; 29 | } else if (c == ']') { 30 | StringBuilder tmp = resStack.pop(); 31 | int count = countStack.pop(); 32 | while (count-- > 0) 33 | tmp.append(res.toString()); 34 | res = tmp; 35 | i++; 36 | } else 37 | res.append(s.charAt(i++)); 38 | } 39 | return res.toString(); 40 | } -------------------------------------------------------------------------------- /398. Random Pick Index.java: -------------------------------------------------------------------------------- 1 | 398. Random Pick Index 2 | 变形版见最后 3 | // https://leetcode.com/problems/random-pick-index/ 4 | ex. 5 | int[] nums = new int[] {1,2,3,3,3}; 6 | Solution solution = new Solution(nums); 7 | // pick(3) should return either index 2, 3, or 4 randomly. Each index should have equal probability of returning. 8 | solution.pick(3); 9 | // pick(1) should return 0. Since in the array only nums[0] is equal to 1. 10 | solution.pick(1); 11 | 12 | Solution: Reservoir Sampling 13 | // For the nth target, ++count is n. Then the probability that rnd.nextInt(++count)==0 is 1/n. Thus, the probability that return nth target is 1/n. 14 | // For (n-1)th target, the probability of returning it is (n-1)/n * 1/(n-1)= 1/n...... 15 | 16 | public class Solution { 17 | int[] nums; 18 | Random r; 19 | public Solution(int[] nums) { 20 | r = new Random(); 21 | this.nums = nums; 22 | } 23 | public int pick(int target) { 24 | int res = -1, count = 0; 25 | for (int i = 0; i < nums.length; i++) { 26 | if (nums[i] != target) continue; 27 | if (r.nextInt(++count) == 0) 28 | res = i; 29 | } 30 | return res; 31 | } 32 | } 33 | 34 | 35 | 变形版:randomly return one of the maximal elements indices 36 | 37 | 注意此题需要先找到cur max使其作为target同时更新res和count值。在求cur max时注意用"if (max == Integer.MIN_VALUE || nums[i] > max)",因为数组中可能有Integer.MIN_VALUE 38 | 39 | public class Solution { 40 | int[] nums; 41 | Random r; 42 | public Solution(int[] nums) { 43 | this.nums = nums; 44 | r = new Random(); 45 | } 46 | public int pick(int target) { 47 | int max = Integer.MIN_VALUE; 48 | int res = -1,count = 0; 49 | for (int i = 0; i < nums.length; i++) 50 | if (max == Integer.MIN_VALUE || nums[i] > max) { //1st time meet the cur max, update res & count 51 | max = nums[i]; 52 | res = i; 53 | count = 1; 54 | } else if (nums[i] == max) { 55 | if (rand.nextInt(++count) == 0) //later meet max, randomly pick 56 | res = i; 57 | } 58 | return res; 59 | } 60 | } 61 | 62 | 63 | 64 | Random Slot 65 | 66 | 给你一个数字n, 代表从1->n  n个slot, 再给一个数组存着空slot的id. 让你同概率下randomly 返回一个非空的slot。 67 | example: 68 | n = 8, slots: 1,2,3,4,5,6,7,8 69 | emptycells = {3, 5} 70 | non empty cells: 1,2,4,6,7,8 71 | return one of non empty cells randomly with equal probability. 72 | 73 | public int returnEmptyCell(int slots , int[] emptyCell){ 74 | Set hs = new HashSet<>(); 75 | for(int i = 0 ; i < emptyCell.length ; i++){ 76 | hs.add(emptyCell[i]); 77 | } 78 | List list = new ArrayList<>(); 79 | for(int i = 1 ; i <= slots ; i++){ 80 | if(!hs.contains(i)){ 81 | list.add(i); 82 | } 83 | } 84 | int rand = new Random().nextInt(list.size()); 85 | return list.get(rand); 86 | } 87 | 88 | -------------------------------------------------------------------------------- /43. Multiply Strings.java: -------------------------------------------------------------------------------- 1 | 43. Multiply Strings 2 | 3 | Given two non-negative integers num1 and num2 represented as strings, return the product of num1 and num2. 4 | Note: 5 | The length of both num1 and num2 is < 110. 6 | Both num1 and num2 contains only digits 0-9. 7 | Both num1 and num2 does not contain any leading zero. 8 | You must not use any built-in BigInteger library or convert the inputs to integer directly. 9 | 10 | 11 | public String multiply(String num1, String num2) { 12 | int m = num1.length(), n = num2.length(); 13 | int[] posNum = new int[m + n]; // important 14 | for (int i = m - 1; i >= 0; i--) 15 | for (int j = n - 1; j >= 0; j--) { 16 | int multiple = (num1.charAt(i) - '0') * (num2.charAt(j) - '0'); 17 | int p1 = i + j, p2 = i + j + 1; 18 | int sum = multiple + posNum[p2]; 19 | posNum[p1] += sum / 10; // important 20 | posNum[p2] = sum % 10; // important 21 | } 22 | StringBuilder sb = new StringBuilder(); 23 | for (int num : posNum) 24 | if (!(sb.length() == 0 && num == 0)) sb.append(num); 25 | return sb.length() == 0 ? "0" : sb.toString(); 26 | } 27 | 28 | 56 29 | * 22 30 | --------- 31 | 112 32 | 112 33 | --------- 34 | -------------------------------------------------------------------------------- /49. Group Anagrams.java: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | }49. Group Anagrams 5 | 6 | Solution 1: hash+counting sort 7 | 8 | O(mn) time, O(m) space, m is the num of strs, n is the length of strs 9 | 10 | public List> groupAnagrams(String[] strs) { 11 | Map> map = new HashMap<>(); 12 | for (String s : strs) { 13 | int[] count = new int[26]; //cuz inputs are lowercase letters, we only need 26 14 | for (int i = 0; i < s.length(); i++) 15 | count[s.charAt(i) - 'a']++; 16 | String anagram = "";//build a string key, eg."aabcccdd" -> 2a1b3c2d 17 | for (int i = 0; i < count.length; i++) 18 | if (count[i] != 0) 19 | anagram += String.valueOf(count[i]) + String.valueOf((char)('a' + i)); 20 | if (!map.containsKey(anagram)) 21 | map.put(anagram, new ArrayList<>()); 22 | map.get(anagram).add(s); 23 | } 24 | return new ArrayList>(map.values()); 25 | } 26 | 27 | 28 | 29 | Solution 2: hash + sort 30 | 31 | O(mnlogn) time, O(m) space, m is the num of strs, n is the length of strs 32 | 33 | public List> groupAnagrams(String[] strs) { 34 | Map> map = new HashMap<>(); 35 | for (String s : strs) { 36 | char[] chrs = s.toCharArray(); 37 | Arrays.sort(chrs); 38 | String t = new String(chrs); 39 | if (!map.containsKey(t)) map.put(t, new ArrayList<>()); 40 | map.get(t).add(s); 41 | } 42 | return new ArrayList>(map.values()); 43 | } -------------------------------------------------------------------------------- /494. TargetSum.java: -------------------------------------------------------------------------------- 1 | 494. Target Sum 2 | // https://leetcode.com/problems/target-sum/ 3 | 4 | Solution 1: subset sum + DP 5 | Time: O(nk) 6 | 7 | The original problem statement is equivalent to: Find a subset of nums that need to be positive and the rest of them negative such that the sum is equal to target. Let P be the positive subset and N be the negative subset 8 | sum(P) - sum(N) = target 9 | sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N) 10 | 2 * sum(P) = target + sum(nums) 11 | So the original problem has been converted to a subset sum problem as follows: 12 | Find a subset P of nums such that sum(P) = (target + sum(nums)) / 2. 13 | Note that the above formula has proved that target + sum(nums) must be even, We can use that fact to quickly identify inputs that do not have a solution 14 | 15 | public int findTargetSumWays(int[] nums, int s) { 16 | int sum = 0; 17 | for (int n : nums) 18 | sum += n; 19 | return sum < s || (s + sum) % 2 > 0 ? 0 : subsetSum(nums, (s + sum) / 2); 20 | } 21 | public int subsetSum(int[] nums, int s) { 22 | int[] dp = new int[s + 1]; 23 | dp[0] = 1; 24 | for (int n : nums) 25 | for (int i = s; i >= n; i--) 26 | dp[i] += dp[i - n]; 27 | return dp[s]; 28 | } 29 | 30 | [subset sum] 31 | //http://algorithms.tutorialhorizon.com/dynamic-programming-subset-sum-problem/ 32 | 33 | 34 | 35 | Solution 2: DFS + memoization 36 | 先找到第一步的所有可能,在每种第一步的可能下再试遍第二步的所有可能……以这种方式试遍所有的组合。但是如果中途发现某一个组合肯定没前途,则立刻放弃这个组合(Backtrack)。 37 | 此题和Combination sum完全不同! 38 | combination sum是每次在数组空间内选择一个数使得最终sum = target,而此题是每次对当前位置的数选择 + 或 -,最终目标是给每个数都赋予符号并使sum = target 39 | 40 | Input: nums is [1, 1, 1, 1, 1], S is 3. 41 | Output: 5 42 | //options: + , - 43 | //map : [[4,4 = 1],[4,2 = 1],[3,3 = 2],[3,1 = 1],[2,2 = 3],[4,-2 = 0],[3,-1 = 0],[2,0 = 1],[1,1 = 4],[4,-4 = 0],[3,-3 = 0],[2,-2 = 0],[1,-1 = 1],[0,0 = 5]] 44 | public int findTargetSumWays(int[] nums, int S) { 45 | Map map = new HashMap<>(); 46 | return dfs(nums, S, 0, map); 47 | } 48 | private int dfs(int[] nums, int sum, int i, Map map) { 49 | String key = i + ": " + sum; 50 | if (map.containsKey(key)) return map.get(key); 51 | if (i == nums.length) 52 | return sum == 0 ? 1 : 0; 53 | int add = dfs(nums, sum - nums[i], i + 1, map); 54 | int minus = dfs(nums, sum + nums[i], i + 1, map); 55 | map.put(key, add + minus); 56 | return add + minus; 57 | } 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /56. Merge Intervals.java: -------------------------------------------------------------------------------- 1 | 56. Merge Interval 2 | // https://leetcode.com/problems/insert-interval/ 3 | // Given [1,3],[2,6],[8,10],[15,18], 4 | // return [1,6],[8,10],[15,18]. 5 | // input is unsorted and has some overlapping intervals, output should be sorted: O(nlogn) time, O(1) space(res doesn't count) 6 | 7 | [注意] 8 | if the format of intervals are "March, 2014" etc, first convert it to "201403" by "2014" + "03"(hashmap:March->03) 9 | or first convert it to 2014 * 12 + 3, if the output is num of months 10 | // http://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=160738&fromuid=109727 11 | 12 | 13 | Solution: 14 | O(nlogn) time, O(1) 15 | 16 | 注意:1.别忘先sort 2.中间用if-else 3.loop后别忘add最后一个interval 17 | 18 | public List merge(List intervals) { 19 | if (intervals.size() <= 1) return intervals; 20 | List res = new ArrayList<>(); 21 | // important 22 | Collections.sort(intervals, new Comparator(){ 23 | public int compare(Interval i1, Interval i2) { 24 | return i1.start - i2.start; 25 | } 26 | }); 27 | int start = intervals.get(0).start, end = intervals.get(0).end; 28 | for (Interval i : intervals) { 29 | if (i.start <= end) 30 | end = Math.max(end,i.end); 31 | else { 32 | res.add(new Interval(start, end)); 33 | start = i.start; 34 | end = i.end; 35 | } 36 | } 37 | res.add(new Interval(start, end)); 38 | return res; 39 | } 40 | /** 41 | * Definition for an interval. 42 | * public class Interval { 43 | * int start; 44 | * int end; 45 | * Interval() { start = 0; end = 0; } 46 | * Interval(int s, int e) { start = s; end = e; } 47 | * } 48 | */ 49 | 50 | 51 | 52 | *******变种******* 53 | 返回总时间 54 | // input is unsorted and has some overlapping intervals, output is the total non-overlapping time; O(nlogn) time, O(1) space 55 | 56 | public int totalTime(List intervals) { 57 | //if (intervals == null || intervals.size() <= 1) return intervals; 58 | Collections.sort(intervals, new Comparator(){ 59 | public int compare(Interval a, Interval b) { 60 | return a.start - b.start; 61 | } 62 | }); 63 | //you can also merge intervals before calculating,which makes calculation easier,but takes some memory(new arraylist) 64 | int total = 0; 65 | Interval prev = new Interval(0, 0); 66 | for (Interval curr : intervals) { 67 | if (prev.end < curr.start) { 68 | total += curr.end - curr.start;//add the whole part(non-overlapping) 69 | prev = curr; 70 | } else if (curr.end > prev.end) { 71 | total += curr.end - prev.end;//only add the non overlapping part after prev.end 72 | prev = curr; 73 | }//else curr.end<=prev.end(curr inside prev),don't calculate anything,and prev isn't updated(prev.end is bigger) 74 | } 75 | return total; 76 | } 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /57. Insert Interval.java: -------------------------------------------------------------------------------- 1 | 57. Insert Interval 2 | // Example 1: 3 | // Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9]. 4 | // Example 2: 5 | // Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16]. 6 | // This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10]. 7 | 8 | 此题思路就是非常straight forward的三步: 9 | 1.add newInterval之前的 10 | 2.add 和newInterval重叠的 11 | 3.add newInterval之后的 12 | 13 | public List insert(List intervals, Interval newInterval) { 14 | List res = new ArrayList<>(); 15 | int i = 0; 16 | while (i < intervals.size() && intervals.get(i).end < newInterval.start) 17 | res.add(intervals.get(i++)); 18 | while (i < intervals.size() && intervals.get(i).start <= newInterval.end) { 19 | newInterval.start = Math.min(intervals.get(i).start, newInterval.start); 20 | newInterval.end = Math.max(intervals.get(i).end, newInterval.end); 21 | i++; 22 | } 23 | res.add(newInterval); 24 | while (i < intervals.size()) res.add(intervals.get(i++)); 25 | return res; 26 | } 27 | 28 | [注意] 29 | // if output is total interval time, then array should be sorted to get the time 30 | // if output should be sorted, we may need to sort the array 31 | // if output should be not overlapping, we may need to merge intervals 32 | 33 | 34 | 35 | /** 36 | * Definition for an interval. 37 | * public class Interval { 38 | * int start; 39 | * int end; 40 | * Interval() { start = 0; end = 0; } 41 | * Interval(int s, int e) { start = s; end = e; } 42 | * } 43 | */ 44 | 45 | 46 | -------------------------------------------------------------------------------- /67. Add Binary.java: -------------------------------------------------------------------------------- 1 | 67. Add Binary 2 | // https://leetcode.com/problems/add-binary/ 3 | 4 | a = "11" 5 | b = "1" 6 | Return "100". 7 | 8 | //if we need to calculate hexadecimal or k decimal, carry = sum / k; res.append(sum % k), and use hash to map 'ABCDEF' to nums 9 | //if we have zeros at the front of strings, and we only need one MS bit,first clear all zeros at the front, after calculaing, 10 | //add '0' if no overflow, add '1' if overflow (length >= 32 or carry == 1) 11 | Solution 1: 12 | 13 | public String addBinary(String a, String b) { 14 | StringBuilder sb = new StringBuilder(); 15 | int i = a.length() - 1, j = b.length() - 1; 16 | int sum = 0; 17 | while (i >= 0 || j >= 0) { 18 | sum /= 2; 19 | if (i >= 0) sum += a.charAt(i--) - '0'; 20 | if (j >= 0) sum += b.charAt(j--) - '0'; 21 | sb.append(sum % 2); 22 | } 23 | if (sum / 2 != 0) sb.append(sum / 2); 24 | return sb.reverse().toString(); 25 | } 26 | 27 | 28 | Solution 2: bit manipulation 29 | // not using +-*/, only use bit manipulations 30 | 31 | public String addBinary(String a, String b) { 32 | StringBuilder res = new StringBuilder(); 33 | int i = a.length() - 1, j = b.length() - 1; 34 | int carry = 0; 35 | while (i >= 0 || j >= 0) { 36 | int num1 = i >= 0 ? Integer.valueOf(String.valueOf(a.charAt(i--))) : 0; 37 | int num2 = j >= 0 ? Integer.valueOf(String.valueOf(a.charAt(j--))) : 0; 38 | int sum = carry ^ num1 ^ num2;//curr digit 39 | carry = (num1 & num2) | (num1 & carry) | (num2 & carry); 40 | res.append(sum);//if don't use StringBuilder,we can use res=String.valueOf(sum%2)+res,then no need to reverse 41 | } 42 | if (carry == 1) res.append(1); 43 | return res.reverse().toString();//append&reverse,instead of inserting at front cuz sb is array-based,insert will be 44 | } 45 | 46 | 47 | -------------------------------------------------------------------------------- /75. Sort Colors.java: -------------------------------------------------------------------------------- 1 | 75. Sort Colors 2 | // https://leetcode.com/problems/sort-colors/ 3 | 4 | // 0,0,1,1,2,1,0,2,2 5 | 6 | public void sortColors(int[] nums) { 7 | int zero = 0, two = nums.length - 1, i = 0; 8 | while (i <= two) { 9 | if (nums[i] == 0) swap(nums, i++, zero++); 10 | else if (nums[i] == 2) swap(nums, i, two--); 11 | else i++; 12 | } 13 | } 14 | private void swap(int[] nums, int i, int j) { 15 | int tmp = nums[i]; 16 | nums[i] = nums[j]; 17 | nums[j] = tmp; 18 | } 19 | 20 | 另一种写法 21 | !!!!!注意!!!!! 22 | for-loop 里是while不是if! 23 | for-loop 条件是<= right不是length! 24 | 25 | public void sortColors(int[] nums) { 26 | int left = 0, right = nums.length - 1; 27 | for (int i = 0; i <= right; i++) { // important: <= right, not < nums.length 28 | while (nums[i] == 2 && i < right) swap(nums, i, right--); //important! while not if !! e.x. [0,1,0] -> [0,1,0] wrong, [0,0,1] correct 29 | while (nums[i] == 0 && i > left) swap(nums, i, left++); 30 | } 31 | } 32 | 33 | ***************变种*************** 34 | sort k colors 35 | // naive:counting sort(O(n) time, need O(k) space, but can be stable if use same idea above) 36 | // below:each time sort min&max, then sort middle part's min&max, until we sort all min&max, O(n) time, O(1) space 37 | public void sortColors2(int[] colors, int k) { 38 | //if (colors == null || colors.length <= 1 || k == 1) return; 39 | int left = 0, right = colors.length - 1; 40 | while (left < right) { 41 | int max = Integer.MIN_VALUE, min = Integer.MAX_VALUE; 42 | for (int i = left; i <= right; i++) { 43 | max = Math.max(max, colors[i]); 44 | min = Math.min(min, colors[i]); 45 | } 46 | int i = left; 47 | while (i <= right) 48 | if (colors[i] == min) swap(colors, i++, left++); 49 | else if (colors[i] > min && colors[i] < max) i++; 50 | else swap(colors, i, right--); 51 | } 52 | } 53 | 54 | 55 | *************变种************* 56 | 给定一个API getCategory(int n), return {L| M| H} 三种category 57 | 第一问 --- 给定一个Array, [4,2,5,7,8,9], 对于每一个int,有一个category,sort them by category 58 | 59 | public void sortByCategory(int[] nums) { 60 | int l = 0, h = nums.length - 1, i = 0; 61 | while (i <= h) { 62 | if (getCategory(nums[i]) == 'L') 63 | swap(nums, i++, l++); 64 | else if (getCategory(nums[i]) == 'R') 65 | swap(nums, i, r--); 66 | else i++; 67 | } 68 | } 69 | 70 | 71 | ********Follow Up******** 72 | 如果这个时候有K个category, 应该怎么办? 73 | 74 | 顺着上一题的思路,我的想法是将(0,1,。。。,k-1) category 分成(0)--> L, (1, k-2) -->M, (k-1) --> H, 然后相同的思想继续call之前的function, 75 | 然后reduce为 (1,k-2)的range,重复之前的事情 76 | 之前的sortCategory也可以处理只有两种Category的case,不用担心, 直接call 77 | 78 | 79 | 80 | 注意:为什么不要increase i, 会问你的!!!!!! 81 | 82 | public void sortKCategory(int[] nums, int k){ 83 | if (nums == null || k <= 0) return; 84 | int categStart = 0, categEnd = k - 1; 85 | while (categStart < categEnd) // stop when only 2-3 categories left 86 | sortCategory(nums, categStart++, categEnd--); 87 | } 88 | 89 | private void sortCategory(int[] nums, int l, int h){ 90 | if (nums == null) return; 91 | int start =0, end = nums.length - 1; 92 | while (getCategory(nums[start]) < l) start++; 93 | while (getCategory(nums[end]) > h) end--; 94 | int i = start; //注意loop条件 95 | while (i <= end) { 96 | if (getCategory(nums[i]) == l) 97 | swap(nums, i++, l++); //注意为什么要increase i 98 | else if (getCategory(nums[i]) == r) 99 | swap(nums, i, r--); //注意为什么不要increase i, 会问你的!!!!!! 100 | else i++; 101 | } 102 | } 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /76. Minimum Window Substring.java: -------------------------------------------------------------------------------- 1 | 76. Minimum Window Substring 2 | // https://leetcode.com/problems/minimum-window-substring/ 3 | S = "ADOBECODEBANC" 4 | T = "ABC" 5 | Minimum window is "BANC". 6 | 7 | public String minWindow(String s, String t) { 8 | int[] count = new int[128]; 9 | for (char c : t.toCharArray()) 10 | count[c]++; 11 | String res = ""; 12 | int start = 0, end = 0, len = t.length(), min = s.length(); 13 | while (end < s.length()) { 14 | if (count[s.charAt(end++)]-- > 0) len--; // valid 15 | while (len == 0) { 16 | if (end - start <= min) { // update min & res 17 | min = end - start; 18 | res = s.substring(start, end); 19 | } 20 | if (count[s.charAt(start++)]++ == 0) len++; // make invalid 21 | } 22 | } 23 | return res; 24 | } 25 | 26 | 扣76, 样的是T给的是set, 会有重复, 样瞬秒, 开始问我时间复杂度,我说O(n)他 开始 顿扯,我说T的size 并 影响,最后 他同意 27 | 最后要我写test case, 后来当T 是空的时候会有问题, 我 上改 bug就结束让我问问题 28 | -------------------------------------------------------------------------------- /90. Subsets II.java: -------------------------------------------------------------------------------- 1 | 90. Subsets II 2 | // https://leetcode.com/problems/subsets-ii/ 3 | If nums = [1,2,2], a solution is: 4 | [ [2], 5 | [1], 6 | [1,2,2], 7 | [2,2], 8 | [1,2], 9 | []] 10 | 11 | public List> subsetsWithDup(int[] nums) { 12 | List> res = new ArrayList<>(); 13 | Arrays.sort(nums); 14 | dfs(res, new ArrayList<>(), nums, 0); 15 | return res; 16 | } 17 | public void dfs(List> res, List tmp, int[] nums, int start) { 18 | res.add(new ArrayList<>(tmp)); 19 | for (int i = start; i < nums.length; i++) { 20 | if (i > start && nums[i] == nums[i - 1]) continue; 21 | tmp.add(nums[i]); 22 | dfs(res, tmp, nums, i + 1); 23 | tmp.remove(tmp.size() - 1); 24 | } 25 | } 26 | 27 | 非递归: 28 | // 1,2,2,3 29 | // res = (),| (1),| (2),(1,2),| (2,2),(1,2,2),| (3),(1,3),(2,3),(2,2,3),(1,2,2,3) 30 | public List> subsetsWithDup(int[] nums) { 31 | List> res = new ArrayList<>(); 32 | Arrays.sort(nums); 33 | res.add(new ArrayList<>()); 34 | int size = 0, start = 0; 35 | for (int i = 0; i < nums.length; i++) { // num to insert 36 | start = (i != 0 && nums[i] == nums[i - 1]) ? size : 0; // prev res size 37 | size = res.size(); // cur res size 38 | for (int j = start; j < size; j++) { // set to be inserted into 39 | List tmp = new ArrayList<>(res.get(j)); // important! 40 | tmp.add(nums[i]); 41 | res.add(tmp); 42 | } 43 | } 44 | return res; 45 | } 46 | 47 | follow up 48 | 有个class,有个方法next(), 每次调用next()输出subsets中的下一个 49 | 50 | 51 | -------------------------------------------------------------------------------- /91. Decode Ways.java: -------------------------------------------------------------------------------- 1 | 91. Decode Ways 2 | // https://leetcode.com/problems/decode-ways/ 3 | 'A' -> 1 4 | 'B' -> 2 5 | ... 6 | 'Z' -> 26 7 | Given an encoded message containing digits, determine the total number of ways to decode it. 8 | For example, 9 | Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). 10 | The number of ways decoding "12" is 2. 11 | 12 | 这道题要求解码方法,跟之前那道 Climbing Stairs 爬梯子问题 非常的相似,但是还有一些其他的限制条件, 13 | 比如说一位数时不能为0,两位数不能大于26,其十位上的数也不能为0,出去这些限制条件,根爬梯子基本没啥区别,也勉强算特殊的斐波那契数列,当然需要用动态规划Dynamci Programming来解 14 | 15 | Test: 16 | "" // empty string 17 | "0" // invalid encoding number 18 | "&*^.abc" // invalid input char 19 | "201" -> 1 // 0 can only be at the units of a two-digit number 20 | "12" -> 2 21 | 22 | 注意: 问输入是否全为数字,若否则还需检测其他非法字符 23 | 24 | Solution 1: DP 25 | public int numDecodings(String s) { 26 | if (s.length() == 0 || s.charAt(0) == '0') return 0; // 27 | int[] dp = new int[s.length() + 1]; 28 | dp[0] = 1; 29 | dp[1] = 1; 30 | for (int i = 1; i < s.length(); i++) { 31 | if (s.charAt(i) != '0') dp[i + 1] = dp[i]; 32 | if (s.charAt(i - 1) != '0' && Integer.valueOf(s.substring(i - 1, i + 1)) <= 26) 33 | dp[i + 1] += dp[i - 1]; 34 | } 35 | return dp[s.length()]; 36 | } 37 | 38 | Solution 2: DFS 39 | Time: O(n) time 40 | 41 | public int numDecodings(String s) { 42 | if (s == null || s.length() == 0) return 0; 43 | return dfs(s, 0); 44 | } 45 | private int dfs(String s, int i) { 46 | if (i == s.length()) return 1; //if the whole string has been decoded, return 1 47 | if (s.charAt(i) == '0') return 0; 48 | if (i < s.length() - 1 && Integer.valueOf(s.substring(i, i + 2) < 26) 49 | return dfs(s, i + 1) + dfs(s, i + 2); 50 | else 51 | return dfs(s, i + 1); 52 | } 53 | 54 | 55 | *************************Follow Up: constant space******************** 56 | Follow up就问 下有没有constant space的解法。 57 | 这段代码非常非常容易出错!一定要好好看好好写! 58 | 59 | public int numDecodings(String s) { 60 | if (s.length() == 0 || s.charAt(0)=='0') return 0; 61 | int dpn_2 = 1, dpn_1 = 1; 62 | for (int i = 1; i < s.length(); i++) { 63 | if (s.charAt(i) == '0') dpn_1 = 0; 64 | int tmp = (Integer.valueOf(s.substring(i - 1, i + 1)) <= 26) ? dpn_1 + dpn_2 : dpn_1; 65 | dpn_2 = dpn_1; 66 | dpn_1 = tmp; 67 | } 68 | return dpn_1; 69 | } 70 | 71 | **************************Follow Up************************** 72 | 如果给的value不连续,比如a:78, b:539, ..., 怎么办。。我说可以 backtracking,然后简单说 下怎么搞。。 73 | 74 | 75 | 76 | 77 | ********变种******** 78 | Return all decode ways 79 | 80 | public List numDecodings(String s) { 81 | List res = new ArrayList<>(); 82 | if (s == null || s.length() == 0) return res; 83 | dfs(res, s, new StringBuilder(), 0); 84 | return res; 85 | } 86 | private void dfs(List res, String s, StringBuilder sb, int i) { 87 | if (i == s.length()) {//if the whole string has been decoded, return 1 88 | res.add(sb.toString()); 89 | return; 90 | } 91 | if (s.charAt(i) == '0') return; 92 | int length = sb.length(); 93 | int num1 = Integer.valueOf(s.substring(i, i + 1)); 94 | dfs(res, s, sb.append((char)('A' + num1 - 1)), i + 1); 95 | sb.setLength(length); 96 | if (i < s.length() - 1 && Integer.valueOf(s.substring(i, i + 2) <= 26) { 97 | int num2 = Integer.valueOf(s.substring(i, i + 2)); 98 | dfs(res, s, sb.append((char)('A' + num2 - 1)), i + 2); 99 | sb.setLength(length); 100 | } 101 | } 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /98. Validate Binary Search Tree.java: -------------------------------------------------------------------------------- 1 | 98. Validate Binary Search Tree 2 | // https://leetcode.com/problems/validate-binary-search-tree/ 3 | 4 | Solution 1: inorder + prev 5 | 6 | Integer prev = null; 7 | public boolean isValidBST(TreeNode root) { 8 | if (root == null) return true; 9 | if(!isValidBST(root.left)) return false; 10 | if (prev != null && prev >= root.val) return false; 11 | prev = root.val; 12 | if (!isValidBST(root.right)) return false; 13 | return true; 14 | } 15 | 16 | 17 | 18 | 19 | Solution 2: MIN - MAX check 20 | 21 | 注意return的写法 22 | 23 | public boolean isValidBST(TreeNode root) { 24 | return checkBST(root, Long.MIN_VALUE, Long.MAX_VALUE); 25 | } 26 | private boolean checkBST(TreeNode root, long min, long max) { 27 | if (root == null) return true; 28 | if (root.val <= min || root.val >= max) return false; 29 | return checkBST(root.left, min, root.val) && checkBST(root.right, root.val, max); 30 | // if (!checkBST(root.left, min, root.val)) return false; 31 | // if (!checkBST(root.right, root.val, max)) return false; 32 | // return true; 33 | } -------------------------------------------------------------------------------- /Behavior.txt: -------------------------------------------------------------------------------- 1 | Behavior 2 | 3 | introduce yourself, what's your favourite project, and the challenging part? 4 | Which team would you like to work with? 5 | What are the technologies you are most interested in? 6 | Why Facebook? 7 | 简历,对FB的了解,对FB哪个Product比较感兴趣,说了15分钟 8 | 举个例子你是如何说服别人的 9 | 10 | 11 | -------------------------------------------------------------------------------- /Bipartite Graph.java: -------------------------------------------------------------------------------- 1 | Bipartite Graph 2 | // http://www.geeksforgeeks.org/bipartite-graph/ 3 | 4 | 5 | class Bipartite { 6 | final static int V = 4; // # of Vertices 7 | 8 | public boolean isBipartite(int G[][], int src) { 9 | // The value 1 is used to indicate first color is assigned and value 0 indicates second color is assigned. 10 | int colorArr[] = new int[V]; 11 | Arrays.fill(colorArr, -1); 12 | colorArr[src] = 1; 13 | Queue q = new LinkedList<>(); 14 | q.add(src); 15 | while (!q.isEmpty()) { 16 | int u = q.poll(); 17 | // Find all non-colored adjacent vertices 18 | for (int v = 0; v < V; ++v) 19 | if (G[u][v] == 1 && colorArr[v] == -1) { 20 | colorArr[v] = 1 - colorArr[u]; 21 | q.add(v); 22 | } else if (G[u][v] == 1 && colorArr[v] == colorArr[u]) return false; 23 | } 24 | return true; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Can Reach (m,n).java: -------------------------------------------------------------------------------- 1 | Can Reach (m,n) 2 | 3 | 给一个Pair (M, N) 代表坐标,你从(1, 1)出发,每次 (x, y) => (x + y, y) or (x, x + y)向右下方移动,如果能达到(M, N)就是True,反之False. 4 | 我一开始说BFS,面试官说不是最优,最优是 O(m+n),然后就到QA环节了。 5 | 6 | 7 | 8 | 思路:从(M, N) 出发,M 和 N 必定一大一小,否则不可能满足上述条件。所以两者中较大是 X + Y, 较小是 X 或 Y。 9 | 由此从右下往左上反推,每一步都只可能有一个路径,所以最终能到达(1, 1)则为 True。 10 | 11 | Time: O(m + n) 12 | 13 | public boolean canReachMN(int m, int n) { 14 | int[] prev = new int[]{m, n}; 15 | while (prev[0] >= 1 && prev[1] >= 1) { 16 | getPreviousPos(prev); 17 | if (prev[0] == 1 && prev[1] == 1) return true; 18 | } 19 | return false; 20 | } 21 | private void getPreviousPos(int[] cur) { 22 | if (cur[0] < cur[1]) cur[1] -= cur[0]; 23 | else cur[0] -= cur[1]; 24 | } 25 | 26 | 此题如果用DP或BFS都是O(m * n)的,而且根本没必要那么做。 -------------------------------------------------------------------------------- /Construct BST from preorder list.java: -------------------------------------------------------------------------------- 1 | Construct BST from preorder list 2 | 3 | // 这个方法是“Construct BST from given preorder traversal”的O(n)解法,使用 MIN-MAX 思想,此题还有O(n^2)解法。 4 | // 参见 http://www.geeksforgeeks.org/construct-bst-from-given-preorder-traversa/ 5 | public int idx = 0; 6 | private TreeNode constructBST(int[] pre) { 7 | return constructBSTfromPreorder(pre, Integer.MIN_VALUE, Integer.MAX_VALUE); 8 | } 9 | private TreeNode constructBSTfromPreorder(int[] pre, int min, int max) { 10 | if (idx >= pre.length) return null; 11 | if (pre[idx] <= min || pre[idx] >= max) return null; 12 | TreeNode root = new TreeNode(pre[idx++]); 13 | root.left = constructBSTfromPreorder(pre, min, root.val); 14 | root.right = constructBSTfromPreorder(pre, root.val, max); 15 | return root; 16 | } 17 | 18 | // For example, if the given traversal is {10, 5, 1, 7, 40, 50}, 19 | // then the output should be root of following tree. 20 | // 10 21 | // / \ 22 | // 5 40 23 | // / \ \ 24 | // 1 7 50 -------------------------------------------------------------------------------- /Convert BST to Circular Doubly LinkedList.java: -------------------------------------------------------------------------------- 1 | Convert BST to Circular Doubly LinkedList 2 | // http://articles.leetcode.com/convert-binary-search-tree-bst-to/ 3 | 4 | 注意,head和prev必须用全局变量!! 5 | 6 | // we could safely modify a node’s left pointer to point to the previously traversed node as we never use it once we reach a node. 7 | // We would also need to modify the previously traversed node’s right pointer to point to the current node. 8 | // But wait, we are still missing two more steps. First, we did not assign the list’s head pointer. Second, the last element’s right pointer does not point to the first element (similar to the first element’s left pointer). 9 | // Just update the current node’s right pointer to point back to the head and the head’s left pointer to point to current node in each recursive call. 10 | // As the recursion ends, the list’s head and tail would be automagically updated with the correct pointers. 11 | // Don’t forget to check for this special case: A list with only one element should have its left and right pointers both pointing back to itself. 12 | 13 | Solution 1: recursion 14 | O(n) time, O(h) space 15 | 16 | TreeNode head = null, prev = null; 17 | public TreeNode convertBSTtoCircularDL(TreeNode root) { 18 | convert(root); 19 | return head; 20 | } 21 | public void convert(TreeNode root) { 22 | if (root == null) return; 23 | convert(root.left); 24 | root.left = prev; 25 | if (prev != null) prev.right = root; 26 | else head = root; 27 | // would make head <-> tail in the end 28 | TreeNode right = root.right; 29 | head.left = root; 30 | root.right = head; 31 | prev = root; 32 | convert(right); 33 | } 34 | 35 | 36 | 37 | Solution 2: iteration 38 | O(n) time, O(h) space 39 | 40 | public TreeNode bstToDoublyList(TreeNode root) { 41 | TreeNode head = null, prev = null; 42 | Stack stack = new Stack<>(); 43 | while (root != null || !stack.empty()) { 44 | while (root != null) { 45 | stack.push(root); 46 | root = root.left; 47 | } 48 | root = stack.pop(); 49 | root.left = prev; 50 | if (prev != null) prev.right = root; 51 | else head = root; 52 | TreeNode right = root.right; 53 | head.left = root; 54 | root.right = head;//remember to update the prev !!! 55 | prev = root; 56 | root = right;//we should root=root.right even if it's null!!! 57 | } 58 | return head; 59 | } 60 | -------------------------------------------------------------------------------- /Count Palindromic Substrings.java: -------------------------------------------------------------------------------- 1 | Count Palindromic Substrings 2 | 找一个字符串所有回文子字符串的个数 3 | 4 | public static int longestPalindrome(String s) { 5 | int start = 0, end = 0, res = 0; 6 | for (int i = 0; i < s.length(); i++) 7 | res += countExpandPalindromes(s, i, i); 8 | for (int i = 0; i < s.length() - 1; i++) 9 | res += countExpandPalindromes(s, i, i + 1); 10 | return res; 11 | } 12 | private static int countExpandPalindromes(String s, int i, int j) { 13 | while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) { 14 | i--; 15 | j++; 16 | } 17 | return (j - i) / 2; 18 | } 19 | 20 | 21 | 伪代码 22 | // for i from 0 through n - 1 23 | // for r that makes both i - r and i + r in range 鏉ユ簮涓€浜�.涓夊垎鍦拌鍧�. 24 | // if charAt(i - r) != charAt(i + r) break; 25 | // count++; 26 | 27 | // for i from 0 though n - 2 28 | // for r that makes both i - r and i + 1 + r in range 29 | // if charAt(i - r) == charAt(i + 1 + r) break 30 | // count++; 31 | 32 | // return count; 33 | 34 | 35 | *******变种******* 36 | 输出所有回文子串, 37 | 在下述代码里改一下即可 38 | 39 | public String longestPalindrome(String s) { 40 | int start = 0, end = 0; 41 | for (int i = 0; i < s.length() - 1; i++) { 42 | int len1 = expandPalindrome(s, i, i); 43 | int len2 = expandPalindrome(s, i, i + 1); 44 | int len = Math.max(len1, len2); 45 | if (len > end - start) { 46 | start = i - (len - 1) / 2; 47 | end = i + len / 2; 48 | } 49 | } 50 | return s.substring(start, end + 1); 51 | } 52 | 53 | 54 | -------------------------------------------------------------------------------- /Dot Product & Variations.java: -------------------------------------------------------------------------------- 1 | Dot Product & Variations 2 | 3 | 1.Basic Dot Product 4 | // assume a, b have same length 5 | public int dotProduct(int[] a, int[] b){ 6 | int res = 0; 7 | for (int i = 0; i < a.length; i++) 8 | res += a[i] * b[i]; 9 | return res; 10 | } 11 | 12 | 13 | 2.Dot product of sparse vector 14 | You have 2 sparse vectors (large number of 0’s). First tell me a way to represent and store them, and then find the dot product. 15 | 面试官先问每个vector很大,不能在内存中存下怎么办,我说只需存下非零元素和他们的下标就行,然后问面试官是否可用预处理后的 16 | 这两个vector非零元素的index和value作为输入,面试官同意后写完O(M*N)的代码(输入未排序,只能一个个找),MN分别是两个vector长度。 17 | 18 | 又问这两个输入如果是根据下标排序好的怎么办,是否可以同时利用两个输入都是排序好这一个特性,最后写出了O(M + N)的双指针方法, 19 | 每次移动pair里index0较小的指针,如果相等则进行计算,再移动两个指针。 20 | 21 | class Node { 22 | int idx, val; 23 | public Node(int idx, int val) { 24 | this.idx = idx; 25 | this.val = val; 26 | } 27 | } 28 | // O(m + n) - like merge sort 29 | public int SparseVectorProduct(int[] a, int[] b){ 30 | List l1 = new ArrayList<>(); 31 | List l2 = new ArrayList<>(); 32 | for (int i = 0; i < a.length; i++) 33 | if (a[i] != 0) l1.add(new Node(i, a[i])); 34 | for (int i = 0; i < b.length; i++) 35 | if (b[i] != 0) l2.add(new Node(i, b[i])); 36 | int res = 0, i = 0, j = 0; 37 | while (i < l1.size() && j < l2.size()) { 38 | if (l1.get(i).idx < l2.get(j).idx) i++; 39 | else if (l1.get(i).idx > l2.get(j).idx) j++; 40 | else res += l1.get(i++).val * l2.get(j++).val; 41 | } 42 | return res; 43 | } 44 | 45 | 46 | 47 | 3.long & short vector 48 | 如果一个 vector 比另一个大很多怎么办,答对于小的 vector 里 每一个(index, value),在大的里 binary search。然后问了复杂度。 49 | 50 | Time: O(n*logm) 51 | 52 | 又问如果两个数组一样长,且一会sparse一会dense怎么办。他说你可以在two pointer的扫描中内置一个切换二分搜索的机制。 53 | 看差值我说过,设计个反馈我说过,他说不好。他期待的解答是,two pointers找到下个位置需要m次比较,而直接二分搜需要log(n)次比较。 54 | 那么在你用two pointers方法移动log(n)次以后,就可以果断切换成二分搜索模式了。 55 | 56 | 57 | // Binary search如果找到了一个元素index,那就用这次的index作为下次binary search的开始。可以节约掉之前的东西,不用search了。 58 | // 然后问,如果找不到呢,如何优化。说如果找不到,也返回上次search结束的index,然后下次接着search。 59 | // 就是上一次找到了,就用这个index继续找这次的;如果找不到,也有一个ending index,就用那个index当starting index。 60 | // 比如[1, 89,100],去找90;如果不存在,那么binary search的ending index应该是89,所以下次就从那个index开始。 61 | // 如果找不到,会返回要插入的位置index + 1,index是要插入的位置,我写的就是返回要插入的index的。 62 | // 但是不管返回89还是100的index都无所谓,反正只差一个,对performance没有明显影响的。 63 | public int sparseVectorProduct(int[] a,int[] b){ 64 | List l1 = new ArrayList<>(); 65 | List l2 = new ArrayList<>(); 66 | for (int i = 0; i < a.length; i++ 67 | if (a[i] != 0) l1.add(new Node(i, a[i])); 68 | for (int i = 0; i < b.length; i++ 69 | if (b[i] != 0) l1.add(new Node(i, b[i])); 70 | if (l1.size() > l2.size()) { 71 | List tmp = l1; 72 | l1 = l2; 73 | l2 = tmp; 74 | } 75 | // [20, 98] [0,1,2,3,..,19,21,..,100] 76 | // [0,48]->[0,23]->[11,23]->[17,23]->[20,23]->[20,20] 77 | int i = 0, j = l2.size() - 1, res = 0; 78 | for (Node n1 : l1) { 79 | j = l2.size() - 1; 80 | while (i <= j) { 81 | int mid = i + (j - i) / 2; 82 | if (l2.get(mid).idx == n1.idx) res += n1.val * l2.get(mid).val; 83 | else if (l2.get(mid).idx < n1.idx) i = mid + 1; 84 | else j = mid - 1; 85 | } 86 | } 87 | return res; 88 | } 89 | 90 | // 楼主:暴力双循环,skip 0. 91 | // 面试官:不急着写,你想想有什么好办法存vector? 92 | // 琢磨了好久,说要不我们用hashmap存value和index 93 | // 面试官继续追问,hashmap会有空的空间,我们有memory限制,你怎么办 94 | // 楼主:那用arraylist存pair? 95 | // 面试官:这个还差不多,那你打算怎么求解? 96 | // 楼主:排序,two pointer? 97 | // 面试官:好,你写吧。写完后追问了时间复杂度 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Find 1st Different Leaf in BST given 2 Preorder arrays.java: -------------------------------------------------------------------------------- 1 | Given two pre-order traversal arrays of two binary search tree respectively, find first pair of non-matching leaves. 2 | 3 | 思路:先建树,然后再找leaf 4 | Time: O(n) 5 | 6 | private static int idx; 7 | public int[] findNotMatchingLeaf(int[] pre1, int[] pre2){ 8 | TreeNode root1 = constructBST(pre1); 9 | TreeNode root2 = constructBST(pre2); 10 | List leaves1 = new ArrayList<>(); 11 | List leaves2 = new ArrayList<>(); 12 | getLeaves(leaves1, root1); 13 | getLeaves(leaves2, root2); 14 | int[] res = new int[2]; 15 | for (int i = 0; i < Math.min(leaves1.size(), leaves2.size()); i++) 16 | if (leaves1.get(i).val != leaves2.get(i).val) { 17 | res[0] = leaves1.get(i).val; 18 | res[1] = leaves2.get(i).val; 19 | return res; 20 | } 21 | return res; 22 | } 23 | // 这个方法是“Construct BST from given preorder traversal”的O(n)解法,使用 MIN-MAX 思想,此题还有O(n^2)解法。 24 | // 参见 http://www.geeksforgeeks.org/construct-bst-from-given-preorder-traversa/ 25 | private TreeNode constructBST(int[] pre) { 26 | idx = 0; 27 | return constructBSTfromPreorder(pre, Integer.MIN_VALUE, Integer.MAX_VALUE); 28 | } 29 | private static TreeNode constructBSTfromPreorder(int[] pre, int min, int max) { 30 | if (idx >= pre.length) return null; 31 | if (pre[idx] <= min || pre[idx] >= max) return null; 32 | TreeNode root = new TreeNode(pre[idx++]); 33 | root.left = constructBSTfromPreorder(pre, min, root.val); 34 | root.right = constructBSTfromPreorder(pre, root.val, max); 35 | return root; 36 | } 37 | private void getLeaves(List res, TreeNode root) { 38 | if (root == null) return; 39 | if (root.left == null && root.right == null) { 40 | res.add(root); 41 | return; 42 | } 43 | getLeaves(res, root.left); 44 | getLeaves(res, root.right); 45 | } 46 | 47 | 48 | 49 | 50 | Follow Up: If they are general binary trees instead of BSTs, could you solve it? give out your reason. 51 | 52 | Time: O(n) 53 | 54 | public int[] findNotMatchingLeaf(String pre1, String pre2){ 55 | int[] res = new int[2]; 56 | String[] str1 = pre1.split("null, null"); 57 | String[] str2 = pre2.split("null, null"); 58 | for (int i = 0;i < Math.min(str1.length(), str2.length()); i++){ 59 | char c1 = str1[i].charAt(str1[i].length() - 2); 60 | char c2 = str2[i].charAt(str2[i].length() - 2); //逗号 61 | if(c1 != c2){ 62 | res[0] = c1 - '0'; 63 | res[1] = c2 - '0'; 64 | return res; 65 | } 66 | } 67 | return res; 68 | } 69 | -------------------------------------------------------------------------------- /Find K Closest Points.java: -------------------------------------------------------------------------------- 1 | Find K Closest Points 2 | 3 | class Point{ 4 | int x; 5 | int y; 6 | public Point(int x, int y) { 7 | this.x = x; 8 | this.y = y; 9 | } 10 | } 11 | 12 | 重点看第二种方法!记住 13 | 14 | Solution 1: MAX Heap 15 | Time: O(nlogk) Space: O(k) 16 | 17 | public Point[] findKClosestPoints(Point[] points, int k, Point target) { 18 | if (points == null || points.length == 0 || k < 1 || k > points.length) return points; 19 | Queue pq = new PriorityQueue<>(k, new Comparator(){ 20 | public int compare(Point p1, Point p2) { 21 | int d1 = (p1.x - target.x) * (p1.x - target.x) + (p1.y - target.y) * (p1.y - target.y); 22 | int d2 = (p2.x - target.x) * (p2.x - target.x) + (p2.y - target.y) * (p2.y - target.y); 23 | return d2 - d1; 24 | } 25 | }); 26 | for (Point p : points) { 27 | pq.offer(p); 28 | if (pq.size() > k) 29 | pq.poll(); 30 | } 31 | Point[] res = new Point[k]; 32 | for (int i = k - 1; i >= 0; i--) 33 | res[i] = pq.poll(); 34 | return res; 35 | } 36 | 37 | 38 | Solution 2: QuickSelect 39 | Time: O(n) average, O(n + klogk) time if output is sorted; O(n^2) worst case 40 | Space: O(1) 41 | 42 | public Point[] findKClosestPoints(Point[] points, int k, Point target) { 43 | if (points.length == 0 || k < 1 || k > points.length) return points; 44 | int left = 0, right = points.length - 1; 45 | while (true) { 46 | int pos = partition(points, left, right, target); 47 | if (pos == k - 1) break; 48 | else if (pos > k - 1) right = pos - 1; 49 | else left = pos + 1; 50 | } 51 | Point[] res = new Point[k]; 52 | for (int i = 0; i < k; i++) 53 | res[i] = points[i]; 54 | return res; 55 | } 56 | 57 | private int partition(Point[] points, int left, int right, Point target) { 58 | shuffle(points); 59 | int idx = left; // important 60 | Point pivot = points[idx]; 61 | int pDist = getDistance(pivot, target); 62 | swap(points, idx, right); 63 | for (int i = left; i < right; i++) { 64 | int iDist = getDistance(points[i], target); 65 | if (iDist < pDist) swap(points, i, idx++); 66 | } 67 | swap(points, idx, right); 68 | return idx; 69 | } 70 | 71 | private int getDistance(Point p, Point target) { 72 | return (p.x - target.x) * (p.x - target.x) + (p.y - target.y) * (p.y - target.y); 73 | } 74 | 75 | private static void swap(Point[] points, int left, int right) { 76 | Point temp = points[left]; 77 | points[left] = points[right]; 78 | points[right] = temp; 79 | } 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /Friend Recommendation.java: -------------------------------------------------------------------------------- 1 | Friend Recommendation 2 | return friends of friends that are not this persons friends 3 | // http://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=210056&extra=page%3D3%26filter%3Dsortid%26sortid%3D311%26searchoption%5B3090%5D%5Bvalue%5D%3D2%26searchoption%5B3090%5D%5Btype%5D%3Dradio%26searchoption%5B3046%5D%5Bvalue%5D%3D2%26searchoption%5B3046%5D%5Btype%5D%3Dradio%26sortid%3D311 4 | 5 | 思路:第二层的friends排序,选出k个共同好友做多的friends 6 | 7 | 8 | Solution 1: Bucket Sort 9 | Time: O(m) Space: O(n) 10 | // m: # of person's friends' friends, n: # of legal recommend friends 11 | 12 | public class Person { 13 | int id; 14 | HashSet friends = new HashSet<>(); 15 | } 16 | private List friendsRecommend(Person person, int k) { 17 | List res = new ArrayList<>(); 18 | if (person == null) return res; 19 | Map map = new HashMap<>(); // recommend id -> count 20 | int b = 0; 21 | for (int friend : person.friends) 22 | for (int recommend : friend.friends) { 23 | int id = recommend.id; 24 | if (person.friends.contains(id) || id == person.id) // don't forget 'id == person.id' 25 | continue; 26 | map.put(id, map.getOrDefault(id, 0) + 1); 27 | b = Math.max(b, map.get(id)); 28 | } 29 | // bucket sort 'recommend list' 30 | List[] buckets = new List[b]; 31 | for (int id : map.keySet()) { 32 | if (buckets[map.get(id)] == null) 33 | buckets[map.get(id)] = new ArrayList(); 34 | buckets[map.get(id)].add(id); 35 | } 36 | //this two loops are O(k) time, when res has k nums, return it 37 | for (int i = b; i >= 0; i--) 38 | for (int j = 0; j < buckets[i].size(); j++) { 39 | res.add(buckets[i].get(j)); 40 | if (res.size() == k) return res; 41 | } 42 | return res; 43 | } 44 | 45 | 46 | Solution 2: Quick Select 47 | Time: average O(m), O(m + n^2) worst case 48 | Space: O(1) space 49 | // m: # of person's friends' friends, n: # of legal recommend friends 50 | public class Person { 51 | int id; 52 | HashSet friends = new HashSet<>(); 53 | } 54 | private List friendsRecommend(Person person, int k) { 55 | List res = new ArrayList<>(); 56 | if (person == null) return res; 57 | Map map = new HashMap<>(); 58 | // O(m) 59 | for (int friend : person.friends) 60 | for (int recommend : friend.friends) { 61 | int id = recommend.id; 62 | if (person.friends.contains(id) || id == person.id) continue; 63 | map.put(id, map.getOrDefault(id, 0) + 1); 64 | } 65 | // O(n) average, O(n^2) worst case 66 | List> list = new ArrayList<>(map.entrySet()); // important 67 | int left = 0, right = list.size() - 1, pos = -1; 68 | while (true) { 69 | pos = partition(list, left, right); 70 | if (pos == k - 1) { 71 | index = pos; 72 | break; 73 | } else if (pos > k - 1) right = pos - 1; 74 | else left = pos + 1; 75 | } 76 | if (pos == -1) return res; 77 | for (int i = 0; i <= pos; i++) { 78 | int id = list.get(i).getKey(); 79 | res.add(id); 80 | } 81 | return res; 82 | } 83 | private int partition(List> list, int left, int right) { 84 | shuffle(list); 85 | int idx = left;//remember to add + left !!! 86 | Map.Entry pivot = list.get(idx); 87 | int pVal = pivot.getValue(); 88 | swap(list, right, idx); 89 | for (int i = left; i < right; i++) 90 | if (list.get(i).getValue() > pVal) swap(list, i, idx++); 91 | swap(list, right, idx); 92 | return idx; 93 | } 94 | private void swap(List> list, int left, int right) { 95 | Map.Entry temp = list.get(left); 96 | list.set(left, list.get(right)); 97 | list.set(right, temp); 98 | } 99 | private void shuffle(List> list) { 100 | final Random random = new Random(); 101 | for(int ind = 1; ind < list.size(); ind++) { 102 | final int r = random.nextInt(ind + 1); 103 | swap(a, ind, r); 104 | } 105 | } 106 | 107 | 108 | 简单版:mutual friends 109 | 已知一个function可以return 给定某人的friends。 找出A B的mutual friends: 110 | 111 | 用hashset 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /K Sum.java: -------------------------------------------------------------------------------- 1 | K Sum 2 | 3 | two sum with duplicate number返回所有的可能的index pairs,我用的是map> 4 | 5 | public List findNumbersThatSumToTarget(int[] arr, int target) { 6 | Map> map = new HashMap<>(); 7 | List res = new ArrayList(); 8 | for (int i = 0; i < arr.length; i++){ 9 | if (!map.containsKey(arr[i])) 10 | map.put(arr[i], new HashSet()); 11 | map.get(arr[i]).add(i); 12 | if (map.containsKey(target - arr[i])){ 13 | for(Integer j: map.get(target - arr[i])) 14 | if(j != i) res.add(new int[]{i, j}); // notice: j != i 15 | } 16 | } 17 | return res; 18 | } 19 | 20 | 21 | 15. 3sum 22 | 此题Follow K sum 可以用递归做,见最后 23 | 24 | 具体代码就是三个for循环,但是index 都是从0开始,所以会有重复 同 个数的问题。然后问我怎么fix这个bug, 就是把每个循环的起始index变成i+1,i是上 层循环的当前 index。 25 | 接下来就问我时间复杂度,有没有 优解。 26 | 27 | 28 | 29 | 30 | // https://leetcode.com/problems/3sum/ 31 | For example, given array S = [-1, 0, 1, 2, -1, -4], 32 | A solution set is: 33 | [[-1, 0, 1], 34 | [-1, -1, 2]] 35 | 36 | 注意先sort,和三次avoid duplicates的代码 37 | 38 | Time: O(n^2) 39 | 40 | public List> threeSum(int[] nums) { 41 | List> res = new ArrayList<>(); 42 | Arrays.sort(nums); 43 | for (int i = 0; i < nums.length - 2; i++) { 44 | if (i > 0 && nums[i] == nums[i - 1]) continue; 45 | int left = i + 1, right = nums.length - 1; 46 | while (left < right) { 47 | if (nums[left] + nums[right] == -nums[i]) { 48 | res.add(Arrays.asList(nums[i], nums[left], nums[right])); // important! see @ NOTICE 49 | while (left < right && nums[left] == nums[left + 1]) left++; 50 | while (left < right && nums[right] == nums[right - 1]) right--; 51 | left++; 52 | right--; 53 | } else if (nums[left] + nums[right] < -nums[i]) { 54 | while (left < right && nums[left] == nums[left + 1]) left++; 55 | left++; 56 | } else { 57 | while (left < right && nums[right] == nums[right - 1]) right--; 58 | right--; 59 | } 60 | } 61 | } 62 | return res; 63 | } 64 | 65 | NOTICE: 66 | 注意参数是Arrays.asList(nums[i], nums[left], nums[right]),不能写作Arrays.asList(new int[]{nums[i], nums[left], nums[right]})! 67 | Arrays的asList方法 68 | JDK 1.4对java.util.Arrays.asList的定义,函数参数是Object[]。所以,在1.4中asList()并不支持基本类型的数组作参数。 69 | JDK 1.5中,java.util.Arrays.asList的定义,函数参数是Varargs, 采用了泛型实现。同时由于autoboxing的支持,使得可以支持对象数组以及基本类型数组。 70 | 不过在使用时,当传入基本数据类型的数组时,会出现小问题,会把传入的数组整个当作返回的List中的第一个元素。 71 | // 所以此题如果用Arrays.asList(new int[]{i, left, right}),LC 的报错是“error: no suitable method found for add(List)”, 72 | // 也就是说编译器把int[]当作参数类型了,而我们真正想要的参数类型是int。印证了上述解释。 73 | 74 | 75 | Follow Up: K Sum 76 | e.x. 4 sum 77 | 其实我们可以考虑用二分法的思路,如果把所有的两两pair都求出来,然后再进行一次Two Sum的匹配,我们知道Two Sum是一个排序加上一个线性的操作, 78 | 并且把所有pair的数量是O((n-1)+(n-2)+...+1)=O(n(n-1)/2)=O(n^2)。所以对O(n^2)的排序如果不用特殊线性排序算法是O(n^2*log(n^2))=O(n^2*2logn)=O(n^2*logn), 79 | 算法复杂度比上一个方法的O(n^3)是有提高的。思路虽然明确,不过细节上会多很多情况要处理。 80 | 首先,我们要对每一个pair建一个数据结构来存储元素的值和对应的index,这样做是为了后面当找到合适的两对pair相加能得到target值时看看他们是否有重叠的index, 81 | 如果有说明它们不是合法的一个结果,因为不是四个不同的元素。接下来我们还得对这些pair进行排序,所以要给pair定义comparable的函数。 82 | 最后,当进行Two Sum的匹配时因为pair不再是一个值,所以不能像Two Sum中那样直接跳过相同的,每一组都得进行查看,这样就会出现重复的情况, 83 | 所以我们还得给每一个四个元素组成的tuple定义hashcode和相等函数,以便可以把当前求得的结果放在一个HashSet里面,这样得到新结果如果是重复的就不加入结果集了。 84 | 85 | 86 | 另附DP的 k-sum:// http://www.cnblogs.com/yuzhangcmu/p/4279676.html 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /Least Removal to Valid Palindromic Subsequence.java: -------------------------------------------------------------------------------- 1 | Least Removal to Valid Palindromic Subsequence 2 | 3 | 做最小的修改把invalid 变成valid,只能delete,但是直接remove比较占时间复杂度。 4 | 5 | 6 | 其中一个方法是求出当前string和它的reversed string的LCS,然后用当前s.length()减去LCS长度就得出最少删除/插入字符的回文了 7 | 你可以试试看,我这个方法是通用的,比如输入abca,它会输出1而不会是3,若输出3那就成了只解决删头尾情况了 8 | 9 | LCS: [YouTube] // https://www.youtube.com/watch?v=NnD96abizww 10 | 11 | public int minRemovalPalindrome(String s) { 12 | if (s == null || s.length() == 0) return 0; 13 | int lcs = longestCommonSubsequence(s, new StringBuilder(s).reverse().toString()); 14 | return s.length() - lcs; 15 | } 16 | private int longestCommonSubsequence(String s, String t) { 17 | int m = s.length(), n = t.length(); 18 | int[][] dp = new int[m + 1][n + 1]; 19 | for (int i = 1; i <= m; i++) 20 | for (int j = 1; j <= n; j++) { 21 | if (s.charAt(i - 1) == t.charAt(j - 1)) 22 | dp[i][j] = dp[i - 1][j - 1] + 1; 23 | else dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); 24 | } 25 | return dp[m][n]; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /LinkedList with Peek & Pop.java: -------------------------------------------------------------------------------- 1 | LinkedList with Peek & Pop 2 | // http://www.1point3acres.com/bbs/forum.php?mod=viewthread&tid=158720&extra=page%3D1%26filter%3Dsortid%26sortid%3D311%26searchoption%255B3090%255D%255Bvalue%255D%3D2%26searchoption%255B3046%255D%255Bvalue%255D%3D2%26searchoption%255B3046%255D%255Btype%255D%3Dradio%25252%2B6sortid%253D311%26searchop_tion%255B3090%255D%255Btype%255D%3Dradio&page=1 3 | 4 | 给一个linkedlist,里面的element都排序好了,但是是一个blackbox,有三个function可以调用。 5 | pop()随机pop出最前面或最后面的element,peek()随机偷看最前面或最后面的element,isEmpty()回传linkedlist是不是空了。 6 | 问设计一个资料结构,list或是array都可以,把linkedlist里面所有的element都拿出来,并保持他们的排序。followup是如果不能用peek()该怎么做。 7 | 8 | 两个链表 small 和 large 9 | 所有pop出来的点 都先接到small的末尾上 如果再pop出来的点比small末尾的那个值要小 就把small末尾的这个点接到large后面 再把这个pop出来的接到small后面 10 | 比如 1->5->7->9->11 11 | 不管先pop出来1 或者11 都先接到small的后面 假设这里pop出来11 就是small->11 12 | 然后再pop出来的点就和这个末尾比较 如果这里pop出来的是9 那么就把11放到上面 Large->11 small->9 13 | 然后如果pop出来1 那么就变成 Large->11->9 small->1 14 | 然后如果pop出来7 Large->11->9 small->1->7 15 | 然后如果pop出来5 Large->11->9->7 smal->1->5 16 | 这样应该就能保证顺序不乱 最后把两个链表拼起来就行了 17 | 18 | // class PeekPopLinkedList { 19 | 20 | // } 21 | 22 | // public LinkedList peekPop() { 23 | // PeekPopLinkedList small = null, large = null; 24 | // while (!isEmpty()) { 25 | // PeekPopLinkedList tmp = pop(); 26 | // if (tmp.val < small) 27 | // } 28 | // } 29 | 30 | 31 | -------------------------------------------------------------------------------- /Longest Arithmetic Subsequence.java: -------------------------------------------------------------------------------- 1 | Longest Arithmetic Subsequence 2 | // http://www.geeksforgeeks.org/length-of-the-longest-arithmatic-progression-in-a-sorted-array/ 3 | 4 | Solution 1: Brute Force 5 | Time: O(n^3) 6 | A simple solution is to one by one consider every pair as first two elements of AP and check for the remaining elements in sorted set. 7 | To consider all pairs as first two elements, we need to run a O(n^2) nested loop. Inside the nested loops, we need a third loop which linearly looks for the more elements in Arithmetic Progression (AP). 8 | This process takes O(n3) time. 9 | 10 | Solution 2: DP 11 | Time: O(n^2) 12 | // We can solve this problem in O(n2) time using Dynamic Programming. To get idea of the DP solution, let us first discuss solution of following simpler problem. 13 | 14 | // Given a sorted set, find if there exist three elements in Arithmetic Progression or not 15 | // Please note that, the answer is true if there are 3 or more elements in AP, otherwise false. 16 | // To find the three elements, we first fix an element as middle element and search for other two (one smaller and one greater). 17 | // We start from the second element and fix every element as middle element. For an element set[j] to be middle of AP, 18 | // there must exist elements ‘set[i]’ and ‘set[k]’ such that set[i] + set[k] = 2*set[j] where 0 <= i < j and j < k <=n-1. 19 | // How to efficiently find i and k for a given j? We can find i and k in linear time using following simple algorithm. 20 | // 1) Initialize i as j-1 and k as j+1 21 | // 2) Do following while i >= 0 and j <= n-1 ......... 22 | // a) If set[i] + set[k] is equal to 2*set[j], then we are done. 23 | // b) If set[i] + set[k] > 2*set[j], then decrement i (do i–-). 24 | // c) Else if set[i] + set[k] < 2*set[j], then increment k (do k++). 25 | 26 | // How to extend the above solution for the original problem? 27 | // The above function returns a boolean value. The required output of original problem is Length of the Longest Arithmetic Progression (LLAP) which is an integer value. 28 | // If the given set has two or more elements, then the value of LLAP is at least 2 (Why?). 29 | 30 | // The idea is to create a 2D table L[n][n]. An entry L[i][j] in this table stores LLAP with set[i] and set[j] as first two elements of AP and j > i. 31 | // The last column of the table is always 2 (Why – see the meaning of L[i][j]). Rest of the table is filled from bottom right to top left. 32 | // To fill rest of the table, j (second element in AP) is first fixed. i and k are searched for a fixed j. 33 | // If i and k are found such that i, j, k form an AP, then the value of L[i][j] is set as L[j][k] + 1. 34 | // Note that the value of L[j][k] must have been filled before as the loop traverses from right to left columns. 35 | 36 | public int longestArithmeticSubsequence(int[] nums) { 37 | if (nums.length < 3) return nums.length; 38 | int n = nums.length, max = 2; 39 | int[][] dp = new int[n][n]; 40 | Arrays.sort(nums); // important!! 41 | // initialize dp[i][n - 1] = 2 42 | for (int i = 0; i < n; i++) 43 | dp[i][n - 1] = 2; 44 | // fix j (consider every nums[j] as second element of AP) to search for valid i & k 45 | for (int j = n - 2; j >= 1; j--) { 46 | int i = j - 1, k = j + 1; 47 | while (i >= 0 && k < n) { 48 | if (nums[i] + nums[k] < 2 * nums[j]) k++; 49 | else if (nums[i] + nums[k] > 2 * nums[j]) { 50 | dp[i][j] = 2; 51 | i--; 52 | } else { 53 | dp[i][j] = dp[j][k] + 1; 54 | max = Math.max(max, dp[i][j]); 55 | i--; 56 | k++; 57 | } 58 | } 59 | // If the loop was stopped due to k becoming more than n-1, set the remaining entties in column j as 2 60 | while (i >= 0) dp[i--][j] = 2; 61 | } 62 | return max; 63 | } 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /Longest Crossing Road.java: -------------------------------------------------------------------------------- 1 | Longest Crossing Road 2 | 3 | 题目:矩阵中由1构成的一横一竖的连续的1,并且这一横一竖有一个交叉点的, 是一条十字路. 4 | 总的来说对每一个1:和他在同一列上,与他相连的的连续的1的数量 + 和同他在同一行上,与他相连的连续的1的数量的和 就是以当前1为交叉点的十字路的长度 5 | 找出矩阵中最长的十字路。 6 | 举几个例子吧. 7 | 8 | 0 0 0 9 | 1 1 1 10 | 1 0 0 中最长的十字路长度是4 11 | 12 | 0 0 1 0 0 0 13 | 0 0 1 1 1 1 14 | 1 1 1 0 1 0 15 | 0 0 1 0 0 1 16 | 中最长的十字路长度是7 17 | 18 | public int maxKilledEnemies(char[][] grid) { 19 | int m = grid.length, n = grid[0].length; 20 | int rowCount = 0, res = 0; 21 | int[] colCount = new int[n]; 22 | for (int i = 0; i < m; i++) 23 | for (int j = 0; j < n; j++) { 24 | if (j == 0) { 25 | rowCount = 0; 26 | for (int k = 0; k < n; k++) 27 | rowCount += grid[i][k] == 1 ? 1 : 0; 28 | } 29 | if (i == 0) { 30 | colCount[j] = 0; 31 | for (int k = 0; k < m; k++) 32 | colCount[j] += grid[k][j] == 1 ? 1 : 0; 33 | } 34 | if (grid[i][j] == 1) 35 | res = Math.max(res, rowCount + colCount[j] - 1); 36 | } 37 | return res; 38 | } -------------------------------------------------------------------------------- /Longest Path in Binary Tree.java: -------------------------------------------------------------------------------- 1 | Longest Path in Binary Tree 2 | 3 | 给个2叉树, 找出从1个叶节点到另1个叶节点最长的路径,返回路径长度 4 | 5 | Solution: post order 6 | 7 | private int max = 0 8 | public int longestPath(TreeNode root) { 9 | dfs(root); 10 | return max; 11 | } 12 | private int dfs(TreeNode root) { 13 | if (root == null) return 0; 14 | int left = dfs(root.left); 15 | int right = dfs(root.right); 16 | max = Math.max(max, left + right + 1); 17 | return Math.max(left, right) + 1; 18 | } 19 | 20 | 此题因为是返回最长长度的话,一定是从叶节点到叶节点,否则,就往叶节点延伸,可以取得更长的长度。 21 | 下题中是返回最大的和,有可能叶节点是负值,所以并不是一定从叶节点出发。但是这两题的解题思路可以是完全一样。 22 | 23 | 24 | 25 | 124. Binary Tree Maximum Path Sum 26 | 27 | Given a binary tree, find the maximum path sum. 28 | 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 must contain at least one node and does not need to go through the root. 29 | Given the below binary tree, 30 | 31 | 1 32 | / \ 33 | 2 3 34 | \ 35 | -1 36 | / 37 | 2 38 | Return 7. 39 | 40 | 41 | private int max = Integer.MIN_VALUE; 42 | public int maxPathSum(TreeNode root) { 43 | dfs(root); 44 | return max; 45 | } 46 | private int dfs(TreeNode root) { 47 | if (root == null) return 0; 48 | int left = Math.max(0, dfs(root.left)); 49 | int right = Math.max(0, dfs(root.right)); 50 | max = Math.max(max, left + right + root.val); 51 | return Math.max(left, right) + root.val; 52 | } 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Merge K Sorted Lists : Array.java: -------------------------------------------------------------------------------- 1 | Merge K Sorted Lists / Array 2 | 3 | 88. Merge Sorted Array 4 | // https://leetcode.com/problems/merge-sorted-array/ 5 | Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. 6 | Note: You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2. 7 | The number of elements initialized in nums1 and nums2 are m and n respectively. 8 | 9 | public void merge(int[] nums1, int m, int[] nums2, int n) { 10 | int k = m + n - 1, i = m - 1, j = n - 1; 11 | while (i >= 0 && j >= 0) { 12 | if (nums1[i] >= nums2[j]) nums1[k--] = nums1[i--]; 13 | else nums1[k--] = nums2[j--]; 14 | } 15 | while (j >= 0) nums1[k--] = nums2[j--]; 16 | } 17 | 18 | 19 | 20 | 21. Merge Two Sorted Lists 21 | //classic iterate 22 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 23 | ListNode dummy = new ListNode(0);//dummy 24 | ListNode p = dummy; 25 | while (l1 != null && l2 != null) { 26 | if (l1.val < l2.val) { 27 | p.next = l1; 28 | l1 = l1.next; 29 | } else { 30 | p.next = l2; 31 | l2 = l2.next; 32 | } 33 | p = p.next; 34 | } 35 | if (l1 != null) p.next = l1; 36 | if (l2 != null) p.next = l2; 37 | return dummy.next; 38 | } 39 | 40 | //recursive 41 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 42 | if (l1 == null) return l2; 43 | if (l2 == null) return l1; 44 | if (l1.val < l2.val) { 45 | l1.next = mergeTwoLists(l1.next, l2); 46 | return l1; 47 | } else { 48 | l2.next = mergeTwoLists(l2.next, l1); 49 | return l2; 50 | } 51 | } 52 | 53 | 54 | 55 | 23. Merge k Sorted Lists 56 | // https://leetcode.com/problems/merge-k-sorted-lists/ 57 | 58 | Solution 1: PriorityQueue 59 | Time: O(nlogk), Space: O(k) 60 | 61 | public ListNode mergeKLists(ListNode[] lists) { 62 | if (lists == null || lists.length == 0) return null; 63 | PriorityQueue pq = new PriorityQueue<>(new Comparator(){ 64 | public int compare(ListNode n1, ListNode n2) { 65 | return n1.val - n2.val; 66 | } 67 | }); 68 | for (ListNode node : lists) 69 | if (node != null) pq.offer(node); 70 | ListNode dummy = new ListNode(0), tail = dummy; 71 | while (!pq.isEmpty()) { 72 | tail.next = pq.poll(); 73 | tail = tail.next; 74 | if (tail.next != null) pq.offer(tail.next); 75 | } 76 | return dummy.next; 77 | } 78 | 79 | 80 | Solution 2: K-Merge Sort 81 | Time: O(nlogk), Space: O(1) 82 | 83 | public ListNode mergeKLists(ListNode[] lists) { 84 | if (lists == null || lists.length == 0) return null; 85 | return mergeKLists(lists, 0, lists.length - 1); 86 | } 87 | private ListNode mergeKLists(ListNode[] lists, int start, int end) { 88 | if (start == end) 89 | return lists[start]; 90 | if (start < end){ 91 | int mid = (end - start) / 2 + start; 92 | ListNode left = mergeKLists(lists, start, mid); 93 | ListNode right = mergeKLists(lists, mid + 1, end); 94 | return mergeTwoLists(left, right); 95 | } 96 | return null; 97 | } 98 | 99 | 100 | // public ListNode mergeKLists(List lists) { 101 | // if (lists.size() == 0) return null; 102 | // if (lists.size() == 1) return lists.get(0); 103 | // if (lists.size() == 2) return mergeTwoLists(lists.get(0), lists.get(1)); 104 | // return mergeTwoLists(mergeKLists(lists.subList(0, lists.size() / 2)), 105 | // mergeKLists(lists.subList(lists.size() / 2, lists.size()))); 106 | // } 107 | 108 | 记住 list.subList(int fromIndex, int toIndex) 方法 109 | 110 | -------------------------------------------------------------------------------- /Mine Sweeper.java: -------------------------------------------------------------------------------- 1 | Mine Sweeper 扫雷 2 | windows里面的扫雷,给一个h,w和m. 生成一个高度h,宽度w,总共m颗雷的矩阵。要求m颗雷随机分布。 3 | 4 | 参见 @Random subset of size K 5 | 6 | Time: O(n) 7 | 8 | public int[][] putBomb(int h, int w, int count){ 9 | Random r = new Random(); 10 | int[] bombLocs = new int[count]; // bomb location array 11 | for (int i = 0; i < count; i++) 12 | bombLocs[i] = i; 13 | for (int i = count; i < h * w; i++) { 14 | int j = r.nextInt(i + 1); 15 | if (j < count) bombLocs[j] = i; 16 | } 17 | int[][] res = new int[h][w]; 18 | for (int i = 0; i < bombLocs.length; i++) { 19 | int x = bombLocs[i] / w; 20 | int y = bombLocs[i] % w; 21 | res[x][y] = 1; 22 | } 23 | return res; 24 | } 25 | 26 | 27 | // http://m.it610.com/article/3096698.htm -------------------------------------------------------------------------------- /Momotonous Array.java: -------------------------------------------------------------------------------- 1 | Momotonous Array 2 | 3 | 判断 个序 是否是递增递减序 4 | 5 | 就一个Boolean flag表示是否已经确定了方向以及方向是什么,从前往后搜。 -------------------------------------------------------------------------------- /Most Frequenct Character in a String.java: -------------------------------------------------------------------------------- 1 | Most Frequenct Character in a String 2 | 3 | 4 | hashmap存频率,然后维持count最大的 5 | public char findMostFrequent(String s) { 6 | Map map=new HashMap<>(); 7 | int count = 0; 8 | char res = ''; 9 | for (int i = 0; i < s.length(); i++) { 10 | char c = s.charAt(i); 11 | Character.toLowerCase(c); // 不区分大小写 12 | if (!Character.isLetterOrDigit(c)) continue; // 去掉其他字符 13 | if (c == ' ') continue; //去掉空格加这个 14 | map.put(c, map.getOrDefault(c, 0)+1); 15 | if (map.get(c) > count) { 16 | count = map.get(c); 17 | res = c; 18 | } 19 | } 20 | return res; 21 | } 22 | 23 | 24 | Follow Up: 25 | 优化时间,count维持两个,频率第一大,第二大,1-2如果>=剩下的,就可以了。 26 | 27 | public char findMostFrequent(String s) { 28 | Map map=new HashMap<>(); 29 | int count1 = 0, count2 = 0; 30 | char c1 = '';//, c2 = ''; 31 | for (int i = 0; i < s.length(); i++) { 32 | char c = s.charAt(i); 33 | if (!Character.isLetterOrDigit(c)) continue; 34 | map.put(c, map.getOrDefault(c, 0)+1); 35 | if (map.get(c) >= count1) { 36 | count2 = count1; 37 | //c2 = c1; 38 | count1 = map.get(c); 39 | c1 = c; 40 | } else if(map.get(c) >= count2){ 41 | count2 = map.get(c); 42 | //c2 = c; 43 | } 44 | if (count1 - count2 >= s.length() - i) 45 | return c1; 46 | } 47 | return c1; 48 | } 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /Power Mod.java: -------------------------------------------------------------------------------- 1 | Power Mod 2 | 3 | Calculates a to the power of b, mod c. 4 | (x*y)%z == ((x%z)*y)%z == (x*(y%z))%z 5 | Examples: 6 | PowMod(2,3,5) = 2*2*2 % 5 = 8%5 =3 7 | PowMod(3, 6, 7) = 3*3*3*3*3*3 % 7 = 729%7 =1. 8 | PowMod(16,16,5) = 1 9 | 10 | Solution: recursion 11 | Time: O(logb) 12 | 13 | public int powmod(int a , int b , int c){ 14 | return pow(a, b) % c; 15 | } 16 | // double a 17 | private int pow(int a, int b) { 18 | if (b == 0) return 1; 19 | if (b % 2 == 0) return pow(a * a, b / 2); 20 | else return a * pow(a * a, b / 2); 21 | } 22 | 23 | 24 | 50. Pow(x, n) 25 | 26 | Solution 1: nested pow 27 | public double myPow(double x, int n) { 28 | if (n < 0) return (1 / x) * myPow(1 / x, -(n + 1)); // not myPow(1 / x, -n) -> will overflow when Integer.MIN_VALUE 29 | if (n == 0) return 1; 30 | if (n == 2) return x * x; 31 | if (n % 2 == 0) return myPow(myPow(x, n / 2), 2); 32 | else return x * myPow(myPow(x, n / 2), 2); 33 | } 34 | 35 | 36 | Solution 2: double x 37 | public double myPow(double x, int n) { 38 | if (n == 0 || x == 1) return 1; // necessary 39 | if (x == -1) return n % 2 == 0 ? 1 : -1; // necessary 40 | if (n == Integer.MIN_VALUE) return 0; 41 | if (n < 0) { 42 | n = -n; 43 | x = 1 / x; 44 | } 45 | return n % 2 == 0 ? myPow(x * x, n / 2) : x * myPow(x * x, n / 2); 46 | } 47 | 48 | 49 | Solution 3: double pow, recursive 50 | public double myPow(double x, int n) { 51 | if (n == 0) return 1; 52 | double tmp = myPow(x, n / 2); 53 | if (n % 2 == 0) return tmp * tmp; 54 | else return n < 0 ? 1 / x * tmp * tmp : x * tmp * tmp; 55 | } 56 | 57 | 58 | Solution 4: double pow, iterative 59 | public double myPow(double x, int n) { 60 | if (n == 0 || x == 1) return 1; 61 | if (x == -1) return n % 2 == 0 ? 1 : -1; 62 | if (n == Integer.MIN_VALUE) return 0; 63 | if (n < 0) { 64 | n = -n; 65 | x = 1 / x; 66 | } 67 | double res = 1; 68 | while (n > 0) { 69 | if ((n & 1) == 1) res *= x; // execude only when odd: n, 1; even: 1 70 | x *= x; // x to the power of 2 71 | n >>= 1; // divide the power by 2 72 | } 73 | return res; 74 | } 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /Previous Permutation.java: -------------------------------------------------------------------------------- 1 | //https://www.nayuki.io/page/next-lexicographical-permutation-algorithm 2 | 3 | Previous Permutation 4 | 5 | 2764135 (找最后一个逆序41) 6 | 2764135 (找4后面比4小的最后一个数3) 7 | 2763145 (交换3,4的位置) 8 | 2763541 (把3后面的1,4,5反转) 9 | 10 | public void previousPermuation(int[] nums) { 11 | if (nums.length < 2) return; 12 | int firstLarger = nums.length - 2; 13 | while (firstLarger >= 0) { 14 | if (nums[firstLarger] > nums[firstLarger + 1]) break; 15 | firstLarger--; 16 | } 17 | if (firstLarger == -1) { 18 | reverse(nums, 0, nums.length - 1); 19 | return; 20 | } 21 | int firstSmaller = nums.length - 1; 22 | while (firstSmaller > firstLarger) { 23 | if (nums[firstSmaller] < nums[firstLarger]) break; 24 | firstSmaller--; 25 | } 26 | swap(nums, firstLarger, firstSmaller); 27 | reverse(nums, firstLarger + 1, nums.length - 1); 28 | } 29 | private void swap(int[] nums, int left, int right) { 30 | int temp = nums[left]; 31 | nums[left++] = nums[right]; 32 | nums[right--] = temp; 33 | } 34 | private void reverse(int[] nums, int left, int right) { 35 | while (left < right) 36 | swap(nums, left++, right--); 37 | } 38 | 39 | 40 | 41 | 42 | 43 | 31. Next Permutation 44 | // https://leetcode.com/problems/next-permutation/ 45 | 46 | 2763541 (找最后一个正序35) 47 | 2763541 (找3后面比3大的最后一个数4) 48 | 2764531 (交换3,4的位置) 49 | 2764135 (把4后面的5,3,1反转) 50 | 51 | public void nextPermutation(int[] nums) { 52 | if (nums.length < 2) return; 53 | int firstSmaller = nums.length - 2; 54 | while (firstSmaller >= 0) { 55 | if (nums[firstSmaller] < nums[firstSmaller + 1]) break; 56 | firstSmaller--; 57 | } 58 | if (firstSmaller == -1) { 59 | reverse(nums, 0, nums.length - 1); 60 | return; 61 | } 62 | int firstLarger = nums.length - 1; 63 | while (firstLarger > firstSmaller) { 64 | if (nums[firstLarger] > nums[firstSmaller]) break; 65 | firstLarger--; 66 | } 67 | swap(nums, firstSmaller, firstLarger); 68 | reverse(nums, firstSmaller + 1, nums.length - 1); 69 | return; 70 | } 71 | private void swap(int[] nums, int i, int j) { 72 | int tmp = nums[i]; 73 | nums[i] = nums[j]; 74 | nums[j] = tmp; 75 | } 76 | private void reverse(int[] nums, int start, int end) { 77 | for (int i = start; i <= (start + end) / 2; i++) 78 | swap(nums, i, start + end - i); 79 | } 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /Print All Paths in a 2D Board.java: -------------------------------------------------------------------------------- 1 | Print All Paths in a 2D Board 2 | 3 | public class Solution { 4 | private int m; 5 | private int n; 6 | public int numIslands(char[][] grid) { 7 | int count=0; 8 | m=grid.length; 9 | if(m==0) return 0; 10 | n=grid[0].length; 11 | dfs(grid,0,0,""); 12 | } 13 | public void dfs(char[][] grid,int i,int j,String s){ 14 | if(i>m||j>n) return; 15 | if(i==m&&j==n) print(s+grid[i][j]); 16 | dfs(grid,i,j+1,s+grid[i][j]+"->"); 17 | dfs(grid,i+1,j,s+grid[i][j]+"->"); 18 | } 19 | } 20 | 21 | 22 | follow up是如果board很大,怎么优化。答用stringbuilder 23 | 24 | public List printAllPath(char[][] board){ 25 | List res = new ArrayList<>(); 26 | StringBuilder sb = new StringBuilder(); 27 | dfs(board,res,sb,0,0); 28 | return res; 29 | } 30 | public void dfs(char[][] b, List res, StringBuilder sb, int x, int y){ 31 | int len = sb.length(); 32 | sb.append(b[y][x]); 33 | 34 | if( x == b[0].length - 1 && y == b.length - 1){ 35 | String s = sb.toString(); 36 | res.add(s); 37 | } else{ 38 | if( x + 1 < b[0].length) dfs(b,res,sb,x+1,y); 39 | if( y + 1 < b.length ) dfs(b,res,sb,x,y+1); 40 | } 41 | sb.setLength(len); 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Facebook-Interview-Coding 2 | 3 | ## 个人整理的Facebook实习面试题目解法 4 | 5 | - 面经时间范围:2016.8-2017.3 6 | - 题目来源:[一亩三分地-面经版](http://www.1point3acres.com/bbs/forum.php?mod=forumdisplay&fid=145&filter=sortid&sortid=311) 7 | - 说明:这些题解大多是论坛里其他同学的解法加了一些个人理解的注解,如有错误,欢迎联系我 8 | 9 | 10 | -------------------------------------------------------------------------------- /Random return number according to weight.java: -------------------------------------------------------------------------------- 1 | Random return number according to weight 2 | // http://www.geeksforgeeks.org/random-number-generator-in-arbitrary-probability-distribution-fashion/ 3 | return a random number from (0,...,n-1) with given weights 4 | 5 | 6 | private static int randomNumber(int[] weights) { 7 | if (weights == null || weights.length == 0) return 0; 8 | int n = weights.length; 9 | for (int i = 1; i < n; i++) 10 | weights[i] += weights[i - 1];//[1,2,4,5,1,3] -> [1,3,7,12,13,16] 11 | Random rand = new Random(); 12 | int num = rand.nextInt(weights[n - 1]);//num is from 0 to 15 13 | return binarySearch(weights, 0, n - 1, num);//returned value is from 0 to n-1 14 | } 15 | //find the leftmost mid that target < weights[mid]; eg.target=10,weight[mid]=12 16 | private static int binarySearch(int[] weights, int start, int end, int target) { 17 | while (start < end) { 18 | int mid = start + (end - start) / 2; 19 | if (target <= weights[mid]) end = mid; 20 | else start = mid + 1; 21 | } 22 | return start; 23 | } 24 | -------------------------------------------------------------------------------- /Random subset of size K.java: -------------------------------------------------------------------------------- 1 | Random subset of size K 2 | 3 | [See @ Wikipedia] // https://en.wikipedia.org/wiki/Reservoir_sampling#Algorithm_R 4 | 5 | 6 | 7 | public int[] selectKItems(int[] nums, int k){ 8 | Random r = new Random(); 9 | int[] res = new int[k]; 10 | for (int i = 0; i < k; i++) 11 | res[i] = nums[i]; 12 | for (int i = k; i < nums.length; i++) { 13 | int j = r.nextInt(i + 1); 14 | if (j < k) 15 | res[j] = nums[i]; // 1/i to be replaced, (i - 1) / i remains -> [(i - 1) / i] * [k / (i - 1)] = k / i : in i-th iteration 16 | } 17 | return res; 18 | } 19 | 20 | 21 | It can be shown that when the algorithm has finished executing, each item in S has equal probability (i.e. k/length(S)) of being chosen for the reservoir. 22 | 23 | To see this, consider the following proof by [induction]. 24 | 25 | After the (i-1) th round, let us assume, the probability of a number being in the reservoir array is k/(i-1). 26 | Since the probability of the number being replaced in the ith round is 1/i, the probability that it survives the ith round is (i-1)/i. 27 | Thus, the probability that a given number is in the reservoir after the ith round is the product of these two probabilities, 28 | i.e. the probability of being in the reservoir after the (i-1)th round, and surviving replacement in the ith round. 29 | This is (k/(i-1)) * ((i-1)/i)=k/i. Hence, the result holds for i, and is therefore true by induction. 30 | k/i,(i+1-k)/ (i+1) 31 | 32 | -------------------------------------------------------------------------------- /Reader Writer Problem.java: -------------------------------------------------------------------------------- 1 | Reader Writer Problem 2 | 给定: 3 | Mutex:. 4 | void lock(); 5 | bool unlock(); 6 | 7 | SharedMutex: 8 | void readerLock();. 9 | void readerUnlock(); 10 | void writerLock(); 11 | void writerUnlock(); 12 | 13 | 14 | 实现下面4个api,自己定义mutex和variable,不管starvation。 15 | 16 | public class ReadWriteLock{ 17 | private int readers = 0; 18 | private int writers = 0; 19 | private int writeRequests = 0; 20 | 21 | public void lockRead() throws InterruptedException{ 22 | lock(); 23 | while(writers > 0 || writeRequests > 0) await(); 24 | readers++; 25 | unlock(); 26 | } 27 | 28 | public void unlockRead(){ 29 | lock(); 30 | readers--; 31 | signal(); 32 | unlock(); 33 | } 34 | 35 | public void lockWrite() throws InterruptedException{ 36 | lock(); 37 | writeRequests++; 38 | while(readers > 0 || writers > 0) await(); 39 | writeRequests--; 40 | writers++; 41 | unlock(); 42 | } 43 | 44 | public void unlockWrite() throws InterruptedException{ 45 | lock(); 46 | writers--; 47 | notifyAll(); 48 | unlock(); 49 | } 50 | } 51 | 52 | 53 | // http://www.1point3acres.com/bbs/forum.php?%20mod=viewthread&tid=215980&extra=page%3D1%26filter%3Dsortid%26sortid%3D311%26searchoption%5B3090%5D%5Bvalue%5D%3D2%26searchop%20tion%5B3090%5D%5Btype%5D%3Dradio%26searchoption%5B3046%5D%5Bvalue%5D%3D2%26searchoption%5B3046%5D%5Btype%5D%3Dradio%2%206sortid%3D311 54 | 55 | 56 | -------------------------------------------------------------------------------- /Run Length Encoding.java: -------------------------------------------------------------------------------- 1 | Run Length Encoding 2 | Given an input string, write a function that returns the Run Length Encoded string for the input string. 3 | 4 | For example, if the input string is “wwwwaaadexxxxxx”, then the function should return “w4a3d1e1x6”. 5 | 6 | time: O(n) 7 | 8 | public String runLength(String s){ 9 | if(s == null || s.length() == 0) return ""; 10 | StringBuilder sb = new StringBuilder(); 11 | int count = 1; 12 | for (int i = 0; i < s.length(); i++) { 13 | while (i < s.length() - 1 && s.charAt(i) == s.charAt(i + 1)) { 14 | count++; 15 | i++; 16 | } 17 | sb.append(s.charAt(i)).append(count); 18 | count = 1; 19 | } 20 | return sb.toString(); 21 | } 22 | -------------------------------------------------------------------------------- /Shifting Matrix.java: -------------------------------------------------------------------------------- 1 | Shifting Matrix 2 | 3 | 一个m x n 的 array 只有 0 和 1 给一个 int k 4 | 需要把 小于 k 数量 连续的 1 变成 0 5 | 连续: 上下左右和四个斜线方向 6 | 这题说的是,当island的面积小于k的时候,把1翻成0 7 | 8 | 9 | 思路:先做dfs来计算面积并把1翻成2,如果面积小于k,再做一次dfs把2翻成0. 最后再把所有的2翻成0 10 | 这题直接bfs就可以了。union find的精髓在于要不断的merge,图是动态变化的,eg:number of islands ii那道题有新的点加进来。 11 | 12 | 13 | Solution 1: 2 DFS 14 | 15 | int[][] dirs = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}}; 16 | int size = 0; 17 | public void shiftingMatrix(char[][] grid, int k) { 18 | int m = grid.length, n = grid[0].length; 19 | for (int i = 0; i < m; i++) 20 | for (int j = 0; j < n; j++) { 21 | if (grid[i][j] == '1') { 22 | size = 0; 23 | dfsSize(grid, i, j); 24 | if (size < k) {// size < k, change original '1'(now '2') to 0 25 | dfsChange(grid, i, j); 26 | } 27 | } 28 | } 29 | // final shift : change '2'(island whose size >= k) back to '1' 30 | for (int i = 0; i < m; i++) 31 | for (int j = 0; j < n; j++) 32 | if (grid[i][j] == '2') grid[i][j] = '1'; 33 | } 34 | private void dfsSize(char[][] grid, int i, int j) { 35 | if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] != '1') 36 | return; 37 | grid[i][j] = '2'; 38 | size++; 39 | for (int[] d : dirs) 40 | dfsSize(grid, i + d[0], j + d[1]); 41 | } 42 | private void dfsChange(char[][] grid, int i, int j) { 43 | if (i < 0 || i >= grid.length || j < 0 || j >= grid[0].length || grid[i][j] != '2') 44 | return; 45 | grid[i][j] = '0'; 46 | for (int[] d : dirs) 47 | dfsChange(grid, i + d[0], j + d[1]); 48 | } -------------------------------------------------------------------------------- /Shortest Knight Move.java: -------------------------------------------------------------------------------- 1 | Shortest Knight Move 2 | 3 | 就是在象棋棋盘上给你两个点A,B,问 个Knight( 哥说,就是骑 那个哈)最少要 步从A跳到B。 珠从来没玩过 国际象棋,于是问Knight咋 。Turns out只要 任意朝向的L形就好。具体来说,如coordinate是(x,y) 那么在这 的 只knight可以跳到 个position中任何 个: (x-2,y-1); (x-2,y+1);(x+2,y-1);(x+2,y+1);(x-1,y+2);(x-1,y-2);(x+1,y-2);(x+1,y+2). 4 | 5 | Solution: BFS 6 | 7 | 此题不需要建立matrix棋盘矩阵,直接使用坐标BFS即可。 8 | 9 | public int shortestKnightMove(int a1, int a2, int b1, int b2) { 10 | int[][] dirs = new int[][]{{1,2},{2,1},{-1,2},{-2,1},{1,-2},{2,-1},{-1,-2},{-2,-1}}; 11 | Queue q = new LinkedList<>(); 12 | boolean[][] visited = new boolean[8][8]; 13 | q.offer(new int[]{a1, a2}); 14 | visited[a1][a2] = true; 15 | int dist = 0; 16 | while (!q.isEmpty()) { 17 | int size = q.size(); 18 | for (int i = 0; i < size; i++) { 19 | int[] pos = q.poll(); 20 | for (int[] d : dirs) { 21 | int x = pos[0] + d[0], y = pos[1] + d[1]; 22 | if (x == b1 && y == b2) return dist + 1; 23 | if (x < 0 || x >= 8 || y < 0 || y >= 8 || visited[x][y]) continue; 24 | visited[x][y] = true; 25 | q.offer(new int[]{x, y}); 26 | } 27 | } 28 | dist++; 29 | } 30 | return -1; 31 | } 32 | -------------------------------------------------------------------------------- /Sort Squared Sorted Array.java: -------------------------------------------------------------------------------- 1 | 360. Sort Transformed Array 2 | // https://leetcode.com/problems/sort-transformed-array/ 3 | nums = [-4, -2, 2, 4], a = 1, b = 3, c = 5, 4 | Result: [3, 9, 15, 33] 5 | nums = [-4, -2, 2, 4], a = -1, b = 3, c = 5 6 | Result: [-23, -5, 1, 7] 7 | 8 | 思路:a > 0 时res从右往左填充 f(x) 值大的那个,a < 0 时从左往右填充 f(x) 值小的那个。 9 | use two pointers i, j and do a merge-sort like process. depending on sign of a, you may want to start from the beginning or end of the transformed array. 10 | For a==0 case, it does not matter what b‘s sign is. 11 | 12 | Test: 13 | a >= 0, a < 0 14 | 15 | public int[] sortTransformedArray(int[] nums, int a, int b, int c) { 16 | int[] res = new int[nums.length]; 17 | int low = 0, high = nums.length - 1; 18 | if (a >= 0) { 19 | int idx = high; 20 | while (idx >= 0) { 21 | if (getValue(nums[low], a, b, c) >= getValue(nums[high], a, b, c)) 22 | res[idx--] = getValue(nums[low++], a, b, c); 23 | else res[idx--] = getValue(nums[high--], a, b, c); 24 | } else if (a < 0){ 25 | int idx = low; 26 | while (idx < res.length) 27 | if (getValue(nums[low], a, b, c) <= getValue(nums[high], a, b, c)) 28 | res[idx++] = getValue(nums[low++], a, b, c); 29 | else res[idx++] = getValue(nums[high--], a, b, c); 30 | } 31 | return res; 32 | } 33 | private int getValue(int x, int a, int b, int c) { 34 | return a * x * x + b * x + c; 35 | } 36 | 37 | 38 | 简单版:对sorted array的数字平方后排序 39 | 40 | public int[] sortSquaredSortedArray(int[] nums) { 41 | int left = 0, right = nums.length - 1, idx = right; 42 | int[] res = new int[nums.length]; 43 | while (idx >= 0) { 44 | if (nums[left] * nums[left] < nums[right] * nums[right]) 45 | res[idx--] = nums[right] * nums[right--]; 46 | else res[idx--] = nums[left] * nums[left++]; 47 | } 48 | return res; 49 | } -------------------------------------------------------------------------------- /Sparce Matrix Multiplication.java: -------------------------------------------------------------------------------- 1 | Sparce Matrix Multiplication 2 | 3 | 4 | public int[][] sparseMatrixMultiplication(int[][] A, int[][] B) { 5 | if (A.length == 0 || A[0].length == 0 || B.length == 0 || B[0].length == 0) 6 | return new int[][]{}; 7 | int m = A.length, n = B.length, d = B[0].length; 8 | int[][] res = new int[m][d]; 9 | Map> map = new HashMap<>(); 10 | for (int i = 0; i < m; i++) { 11 | Map temp = new HashMap<>(); 12 | for (int j = 0; j < n; j++) 13 | if (A[i][j] != 0) temp.put(j, A[i][j]); 14 | map.put(i, temp); 15 | } 16 | for (int key1 : map.keySet()) { 17 | for (int i = 0; i < d; i++) { 18 | for (int key2 : map.get(key1).keySet()) { 19 | res[key1][i] += map.get(key1).get(key2) * B[key2][i]; 20 | } 21 | } 22 | } 23 | return res; 24 | } 25 | 26 | 27 | public class Solution {//assume inputs are like {{2, 4}, {0, 10}, {3, 15}},index0 is index of non-zero vals,index1 is the val 28 | private Comparator> sparseVectorComparator = new Comparator>(){ 29 | public int compare(ArrayList a, ArrayList b) { 30 | return a.get(0) - b.get(0); 31 | } 32 | };//remember to add ";" !!! 33 | 34 | public int sparseVectorMultiplication(ArrayList> a, ArrayList> b) { 35 | if (a == null || b == null || a.size() == 0 || b.size() == 0) { 36 | return 0; 37 | } 38 | int m = a.size(); 39 | int n = b.size(); 40 | int res = 0; 41 | 42 | //two inputs are unsorted, directly iterate the elements(brute force); O(m*n) time; if use sort, O(mlogm + nlogn) 43 | for (int i = 0; i < m; i++) { 44 | ArrayList pairA = a.get(i); 45 | for (int j = 0; j < n; j++) { 46 | ArrayList pairB = b.get(i); 47 | if (pairA.get(0) == pairB.get(0)) {//if their indices are the same, calculate and break 48 | res += pairA.get(1) * pairB.get(1); 49 | break;//pairA has been calculated, jump to next pair 50 | } 51 | } 52 | } 53 | 54 | //if we need to sort the inputs 55 | Collections.sort(a, sparseVectorComparator); 56 | 57 | //two inputs are sorted by index0, use two pointers(move the smaller, calculate the equal); O(m+n) time 58 | int i = 0; 59 | int j = 0; 60 | while (i < m && j < n) { 61 | ArrayList pairA = a.get(i); 62 | ArrayList pairB = b.get(j); 63 | if (pairA.get(0) < pairB.get(0)) { 64 | i++; 65 | } else if (pairA.get(0) > pairB.get(0)) { 66 | j++; 67 | } else { 68 | res += pairA.get(1) * pairB.get(1); 69 | i++; 70 | j++; 71 | } 72 | } 73 | 74 | //two inputs are sorted by index0, have same size, sometimes dense, sometimes sparse; two pointes + binary search 75 | int i = 0; 76 | int j = 0; 77 | int countA = 0; 78 | int countB = 0; 79 | while (i < m && j < n) { 80 | ArrayList pairA = a.get(i); 81 | ArrayList pairB = b.get(j); 82 | if (pairA.get(0) < pairB.get(0)) { 83 | i++; 84 | countA++; 85 | countB = 0; 86 | if (countA > Math.log(m)) { 87 | i = search(a, i, m, pairB.get(0)); 88 | countA = 0; 89 | } 90 | } else if (pairA.get(0) > pairB.get(0)) { 91 | j++; 92 | countB++; 93 | countA = 0; 94 | if (countB > Math.log(n)) { 95 | j = search(b, j, n, pairA.get(0)); 96 | countB = 0; 97 | } 98 | } else { 99 | res += pairA.get(1) * pairB.get(1); 100 | i++; 101 | j++; 102 | countA = 0; 103 | countB = 0; 104 | } 105 | } 106 | 107 | //two inputs are sorted by index0, input b is much larger than input a, iterate a and binary search b; O(m*logn) time 108 | int i = 0; 109 | int j = 0; 110 | while (i < m) { 111 | ArrayList pairA = a.get(i++); 112 | j = search(b, j, n, pairA.get(0)); 113 | ArrayList pairB = b.get(j++); 114 | if (pairA.get(0) == pairB.get(0)) { 115 | res += pairA.get(1) * pairB.get(1); 116 | } 117 | } 118 | 119 | return res; 120 | } 121 | 122 | private int search(ArrayList> array, int start, int end, int target) { 123 | while (start + 1 < end) { 124 | int mid = start + (end - start) / 2; 125 | ArrayList pair = array.get(mid); 126 | if (pair.get(0) == target) { 127 | return mid; 128 | } else if (pair.get(0) < target) { 129 | start = mid; 130 | } else { 131 | end = mid; 132 | } 133 | } 134 | if (array.get(end).get(0) == target) { 135 | return end; 136 | } 137 | return start; 138 | } 139 | } 140 | 面试官先问每个vector很大,不能在内存中存下怎么办,我说只需存下非零元素和他们的下标就行,然后问面试官是否可用预处理后的 141 | 这两个vector非零元素的index和value作为输入,面试官同意后写完O(M*N)的代码(输入未排序,只能一个个找),MN分别是两个vector长度。 142 | 143 | 又问这两个输入如果是根据下标排序好的怎么办,是否可以同时利用两个输入都是排序好这一个特性,最后写出了O(M + N)的双指针方法, 144 | 每次移动pair里index0较小的指针,如果相等则进行计算,再移动两个指针。 145 | 146 | 又问如果一个向量比另一个长很多怎么办,我说可以遍历长度短的那一个,然后用二分搜索的方法在另一个vector中找index相同的那个元素, 147 | 相乘加入到结果中,这样的话复杂度就是O(M*logN)。 148 | 149 | 又问如果两个数组一样长,且一会sparse一会dense怎么办。他说你可以在two pointer的扫描中内置一个切换二分搜索的机制。 150 | 看差值我说过,设计个反馈我说过,他说不好。他期待的解答是,two pointers找到下个位置需要m次比较,而直接二分搜需要log(n)次比较。 151 | 那么在你用two pointers方法移动log(n)次以后,就可以果断切换成二分搜索模式了。 152 | 153 | Binary search如果找到了一个元素index,那就用这次的index作为下次binary search的开始。可以节约掉之前的东西,不用search了。 154 | 然后问,如果找不到呢,如何优化。说如果找不到,也返回上次search结束的index,然后下次接着search。 155 | 就是上一次找到了,就用这个index继续找这次的;如果找不到,也有一个ending index,就用那个index当starting index。 156 | 比如[1, 89,100],去找90;如果不存在,那么binary search的ending index应该是89,所以下次就从那个index开始。 157 | 如果找不到,会返回要插入的位置index + 1,index是要插入的位置,我写的就是返回要插入的index的。 158 | 但是不管返回89还是100的index都无所谓,反正只差一个,对performance没有明显影响的。 159 | 160 | 161 | public class Solution { 162 | public int[][] multiply(int[][] a, int[][] b) { 163 | if (a == null || b == null) { 164 | return new int[0][0]; 165 | }//for a i*k matrix multiply by a k*j matrix, we will get a i*j matrix 166 | int[][] res = new int[a.length][b[0].length];//res[i][j] = a[i][0]*b[0][j] + a[i][1]*b[1][j] +...+ a[i][k]*b[k][j]; 167 | for (int i = 0; i < a.length; i++) { 168 | for (int k = 0; k < a[0].length; k++) { 169 | if (a[i][k] != 0) {//cuz it's a sparse matrix, we can only calculate nonzero product to reduce operations 170 | for (int j = 0; j < b[0].length; j++) { 171 | if (b[k][j] != 0) {//we only add up all products that a[i][k] != 0 && b[k][j] != 0 to reduct time 172 | res[i][j] += a[i][k] * b[k][j];// +=, not =; *, not + !!! 173 | } 174 | } 175 | } 176 | } 177 | } 178 | return res; 179 | } 180 | } 181 | 182 | // Let's look at brute force solution: 183 | public int[][] multiply_bruteForce(int[][] A, int[][] B) { 184 | int m = A.length, n = A[0].length; 185 | int nB = B[0].length; 186 | int [][] C = new int[m][nB]; 187 | for (int i = 0; i set = new HashSet<>(); 8 | for (int i = 0; i < nums.length; i++) { 9 | sum += nums[i]; 10 | if (sum == k || map.containsKey(sum - k)) return true; 11 | set.add(sum); 12 | } 13 | return false; 14 | } 15 | 16 | 17 | 209. Minimum Size Subarray Sum 18 | 19 | public int minSubArrayLen(int s, int[] nums) { 20 | if (nums == null || nums.length == 0) return 0; 21 | int sum = 0, i = 0, j = 0, min = Integer.MAX_VALUE; 22 | while (j < nums.length) { 23 | sum += nums[j++]; 24 | while (sum >= s) { 25 | min = Math.min(min, j - i); 26 | sum -= nums[i++]; 27 | } 28 | } 29 | return min == Integer.MAX_VALUE ? 0 : min; 30 | } 31 | 32 | 33 | 34 | 325. Maximum Size Subarray Sum Equals k 35 | 36 | public int maxSubArrayLen(int[] nums, int k) { 37 | int sum = 0, max = 0; 38 | Map map = new HashMap<>(); 39 | for (int i = 0; i < nums.length; i++) { 40 | sum += nums[i]; 41 | if (sum == k) max = i + 1; 42 | else if (map.containsKey(sum - k)) 43 | max = Math.max(max, i - map.get(sum - k)); 44 | if (!map.containsKey(sum)) map.put(sum, i); 45 | } 46 | return max; 47 | } 48 | 49 | 这两道题的解法完全不同:这道题由于是求“equal”,所以用“hash”;上一题是求“大于等于”,所以是用two pointers尺取法。 50 | 而且由于两道题的要求不同,它们的输入数据也不同:这道题的输入数据可正可负;上一题却只能是非负数。 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Swap Sort.java: -------------------------------------------------------------------------------- 1 | Swap Sort 2 | 给一个数组,至多允许swap数组里的任意两个数字一次,问是否可以通过swap实现数组排序。 3 | 4 | 第一种肯定对的解法:另复制一个数组然后排序,跟原来的比较,如果有两个以上数字不一样,不能,两个或两个以下,可以 5 | 第二种:需要先过一遍数组,找第一个大于下面的元素,如果没找到代表已经sorted返回true。找到的话,找这个元素后面的最小的值,然后swap一下看之后的数字是否是sorted的。这样子需要2-pass,时间O(n),不需要sort 6 | 7 | public class Solution { 8 | public swapSort { 9 | int c1=-1; 10 | int c2=-1; 11 | for(int i=1;i=0;i--){ 18 | if(nums[i]>nums[i+1]){ 19 | c2=i+1; 20 | break; 21 | } 22 | } 23 | int temp=nums[c1]; 24 | nums[c1]=nums[c2]; 25 | nums[c2]=temp; 26 | for(int i=0;iTask schedule with cool down time 2 | 3 | 给了一串task,不同的task可能属于不同type。这些task要放到CPU里运行,运行同一种type是要考虑一个冷却时间。。。弄了半天,过了好几个例子才搞明白, 4 | 类似于一个OS。给你一个单线程的scheduler,和eg. 4种thread:1,2,3,4, 冷却时间: 3, 5 | 在multithreading的时候同类型的thread要等上一个thread跑完冷却时间之后才能运行,求最后scheduler用了多少time slot。 6 | 7 | 举个例子,thread: 1, 2, 1, 1, 3, 4; 冷却时间: 2 time slot,scheduler应该是这样的:1, 2, _, 1, _, _, 1, 3, 4,最后返回9. 8 | 9 | 10 | 1,最正常的task schedule:输出的是最后的时间 11 | private static int taskSchedule1(int[] tasks, int cooldown) { 12 | if (tasks == null || tasks.length == 0) return 0; 13 | HashMap map = new HashMap<>(); 14 | int slots = 0; 15 | for (int task : tasks) { 16 | //if we need to wait for the cooldown of the same task, just update the slots 17 | if (map.containsKey(task) && map.get(task) > slots) 18 | slots = map.get(task); 19 | //update the time slot to the time when curr task can be done again 20 | map.put(task, slots + 1 + cooldown); 21 | slots++; //important!! update the used 1 slot of curr task 22 | } 23 | return slots; 24 | } 25 | 26 | 27 | 2,最正常的task schedule:输出的是字符串 '_' 28 | //if we need to output a string of the task scheduling(without reordering), eg.1,2,1,1,3,4, k=2, -> 12_1__134 29 | public String taskSchedule2(int[] tasks, int cooldown) { 30 | if (tasks == null || tasks.length == 0) return ""; 31 | Map map = new HashMap<>();//store indices, where cooldown stops, of tasks in window 32 | int slots = 0; 33 | StringBuilder sb = new StringBuilder(); 34 | for (int task : tasks) { 35 | if (map.containsKey(task) && map.get(task) > slots) { 36 | int waitingTime = map.get(task) - slots; 37 | while (waitingTime-- > 0) 38 | sb.append("_"); 39 | slots = map.get(task); 40 | } 41 | map.put(task, slots + cooldown + 1); 42 | sb.append(task); 43 | slots++; 44 | } 45 | return sb.toString(); 46 | } 47 | 48 | 49 | 3,无序的,频率统计的做法,算最后时间 50 | //if tasks can be reordered, output the minimum time needed: O(n) time, O(n) space 51 | private static int taskSchedule3(int[] tasks, int cooldown) { 52 | HashMap map = new HashMap<>(); 53 | for (int task : tasks) 54 | map.put(task, map.getOrDefault(task, 0) + 1); 55 | int maxFrequency = 0, countOfMax = 0; 56 | for (int frequency : map.values()) 57 | if (frequency > maxFrequency) { 58 | maxFrequency = frequency; 59 | countOfMax = 1; 60 | } else if (frequency == maxFrequency) { 61 | countOfMax++; 62 | } 63 | int minimumTime = (maxFrequency - 1) * (cooldown + 1) + countOfMax; 64 | return Math.max(minimumTime, tasks.length); 65 | } 66 | //(maxFrequency - 1) * (cooldown + 1) + countOfMax; 67 | //(maxFrequency - 1): number of minimum time interval; (cooldown + 1): length of each minimum time interval; 68 | //countOfMax: the number of tasks at the end (the cooldown of these tasks don't need to be filled) 69 | //eg. 1113, cooldown = 0, minimumTime = (3-1)*1 + 1 = 3, task.length = 4, we should return 4 70 | //eg. 1123, cooldown = 1, minimumTime = (2-1)*2 + 1 = 3, task.length = 4, we should return 4 71 | //eg. 11122, cooldown = 2, minimumTime = (3-1)*3 + 1 = 7 (1 2 _ 1 2 _ 1), task.length = 5, we should return 7 72 | 4,无序的,统计频率的做法,输出最后字符串 73 | /** 74 | * Find the task that appears for the most time 75 | * Use a map to count the number of the times the task appears then get the maximum count 76 | * the result is decided by the maximum count and the number of tasks with maximum count 77 | * 78 | * two conditions: 79 | * 1. 5 4 _ _ _ 5 4 _ _ _ 5 4 _ _ _ 5 4 the rest tasks cannot fill the empty slots 80 | * 5 4 3 2 _ 5 4 3 2 _ 5 4 _ _ _ 5 4 81 | * the answer is (maxCount - 1) * (interval + 1) + CountOfMax 82 | * 1. 5 4 _ _ _ 5 4 _ _ _ 5 4 _ _ _ 5 4 the rest tasks cannot fill the empty slots 83 | * 5 4 3 2 1 6 5 4 3 2 1 6 5 4 6 _ _ 5 4 84 | * the answer is the length of the nums 85 | * the task which does not have max count first fills the empty slots and then just insert any valid place 86 | * */ 87 | 88 | //output a sequence of tasks that takes least time:O(maxFrequency*klogk) time,O(n) space,n is number of unique tasks 89 | private static String taskSchedule4(String str, int k) { 90 | StringBuilder rearranged = new StringBuilder(); 91 | Map map = new HashMap<>(); 92 | for (char c : str.toCharArray()) { 93 | if (!map.containsKey(c)) { 94 | map.put(c, 0); 95 | } 96 | map.put(c, map.get(c) + 1); 97 | } 98 | 99 | Queue> maxHeap = new PriorityQueue<>(new Comparator>() { 100 | public int compare(Map.Entry entry1, Map.Entry entry2) { 101 | return entry2.getValue() - entry1.getValue(); 102 | } 103 | }); 104 | maxHeap.addAll(map.entrySet());//O(nlogn) time, O(n) space 105 | ArrayList> temp = new ArrayList<>();//O(k) space 106 | 107 | while (!maxHeap.isEmpty()) {//O(max frequency) time 108 | int i = 0; 109 | temp.clear(); 110 | while (i <= k && !maxHeap.isEmpty()) {//O(k) time 111 | Map.Entry curr = maxHeap.poll(); 112 | rearranged.append(curr.getKey()); 113 | curr.setValue(curr.getValue() - 1); 114 | temp.add(curr); 115 | i++; 116 | } 117 | 118 | //add this code if we wanna add _ to show that we need to wait for cooldown, eg.AABB, 2 -> AB_AB 119 | while (i <= k) {//i <= k, not i < k !!! 120 | rearranged.append("_"); 121 | i++;//remember to add i++ !!! 122 | } 123 | 124 | for (Map.Entry e : temp) {//O(klogk) time 125 | if (e.getValue() > 0) { 126 | maxHeap.offer(e); 127 | } 128 | } 129 | } 130 | 131 | //add this code if we add "_" to the string, we need to delete all the "_" at the tail, eg.A__A__ -> A__A 132 | for (int i = rearranged.length() - 1; i >= 0 && rearranged.charAt(i) == '_'; i--) { 133 | rearranged.deleteCharAt(i); 134 | } 135 | 136 | return rearranged.toString(); 137 | } 138 | } 139 | 5,//if cooldown is very small, but there are lots of tasks, how to reduce space? O(cooldown) space 140 | private static int taskSchedule2(int[] tasks, int cooldown) { 141 | if (tasks == null || tasks.length == 0) { 142 | return 0; 143 | } 144 | Queue queue = new LinkedList<>();//store tasks that are waiting for cooldown? 145 | HashMap map = new HashMap<>();//store indices, where cooldown stops, of tasks in window 146 | int slots = 0; 147 | for (int task : tasks) { 148 | if (map.containsKey(task) && map.get(task) > slots) { 149 | //add this code if our output is a string, eg.AA, 2 -> A__A 150 | //int waitingTime = map.get(task) - slots; 151 | //for (int i = 0; i < waitingTime; i++) { 152 | // sb.append("_"); 153 | //} 154 | slots = map.get(task);//if we need to wait for the cooldown of the same task, just update the slots 155 | } 156 | if (queue.size() == cooldown + 1) { 157 | map.remove(queue.poll());//we should do this after updating the slots, cuz we store indices of cooldown 158 | }//stops, we don't know whether we have any idol period between these two same tasks yet, so update it first 159 | map.put(task, slots + cooldown + 1);//update the time slot to the time when curr task can be done again 160 | queue.offer(task); 161 | slots++;//update the used 1 slot of curr task 162 | } 163 | return slots; 164 | } 165 | --------------------------------------------------------------------------------