├── README.md ├── Solutions ├── Images │ ├── 7桥问题.png │ ├── All Anagrams1.png │ ├── Bit_XOR_Equal.png │ ├── Flights_Bug.png │ ├── negative_edge.png │ ├── Bit_ALL_ON_1_9.png │ ├── Bit_XOR_Equal2.png │ ├── Bit_XOR_Equal3.png │ ├── Bit_XOR_Equal4.png │ ├── Bit_XOR_Equal5.png │ ├── Bit_XOR_Equal6.png │ ├── negative_weight.png │ ├── BellmanFord_demo1.png │ ├── BellmanFord_demo2.png │ ├── BellmanFord_demo3.png │ ├── BellmanFord_demo4.png │ ├── BellmanFord_demo5.png │ ├── Bipartite_Example1.png │ ├── Flights_NoResult.png │ ├── Heapify_Analysis1.png │ ├── Bipartite_Example1_BFS.png │ ├── Bipartite_Example1_DFS.jpeg │ ├── Bipartite_Example2_BFS.jpeg │ ├── Bipartite_Example2_DFS.jpeg │ ├── Flights_13Edges_Example.png │ ├── 622_Design_Circular_Queue.png │ ├── 641_Design_Circular_Deque.png │ ├── 936_Stamping_The_Sequence.png │ ├── 406-Diagonal-Sum-of-a-Binary-Tree.png │ └── HeapifyVSOfferAndPercolateUp_TC.png ├── BinarySearch.md ├── String and Array │ ├── 560. Subarray Sum Equals K.md │ ├── 325. Maximum Size Subarray Sum Equals k.md │ ├── String Compress and Decompress.md │ ├── 2375. Construct Smallest Number From DI String.md │ ├── 2163. Minimum Difference in Sums After Removal of Elements.md │ ├── 150. Evaluate Reverse Polish Notation.md │ ├── 1209. Remove All Adjacent Duplicates in String II.md │ ├── 484. Find Permutation.md │ ├── 1249. Minimum Remove to Make Valid Parentheses.md │ ├── 32. Longest Valid Parentheses.md │ ├── 394. Decode String.md │ └── 727. Minimum Window Subsequence.md ├── Misc │ ├── 56. Merge Intervals.md │ ├── 646. Maximum Length of Pair Chain.md │ ├── 715. Range Module.md │ ├── 2080. Range Frequency Queries.md │ ├── 975. Odd Even Jump.md │ ├── 2402. Meeting Rooms III.md │ └── OAs.md ├── DP │ ├── 1824. Minimum Sideway Jumps.md │ ├── 2321. Maximum Score Of Spliced Array.md │ ├── 894. All Possible Full Binary Trees.md │ ├── 1140. Stone Game II.md │ ├── 2318. Number of Distinct Roll Sequences.md │ ├── 1771. Maximize Palindrome Length From Subsequences.md │ ├── 2312. Selling Pieces of Wood.md │ ├── 312. Burst Balloons.md │ ├── 474. Ones and Zeroes.md │ ├── 2262. Total Appeal of A String.md │ ├── 494. Target Sum.md │ ├── 1326. Minimum Number of Taps to Open to Water a Garden.md │ ├── 935. Knight Dialer.md │ ├── 1937. Maximum Number of Points with Cost.md │ ├── 2355. Maximum Number of Books You Can Take.md │ ├── 1024. Video Stitching.md │ ├── 740. Delete and Earn.md │ ├── 1092. Shortest Common Supersequence.md │ ├── 552. Student Attendance Record II.md │ ├── 1312. Minimum Insertion Steps to Make a String Palindrome.md │ ├── 416. Partition Equal Subset Sum.md │ └── 256. Paint House.md ├── GraphSearch │ ├── 1631. Path With Minimum Effort.md │ ├── 847. Shortest Path Visiting All Nodes.md │ ├── 2497. Maximum Star Sum of a Graph.md │ ├── 317. Shortest Distance from All Buildings.md │ ├── 399. Evaluate Division.md │ └── 91. Array Hopper IV.md ├── Stack and Queue │ ├── 622. Design Circular Queue.md │ ├── 353. Design Snake Game.md │ └── 853. Car Fleet.md ├── Monotonic Stack │ ├── 862. Shortest Subarray with Sum at Least K.md │ ├── 2104. Sum of Subarray Ranges.md │ ├── 316. Remove Duplicate Letters.md │ └── 84. Largest Rectangle in Histogram.md ├── Tree │ ├── 2246. Longest Path With Different Adjacent Characters.md │ ├── 863. All Nodes Distance K in Binary Tree.md │ ├── 687. Longest Univalue Path.md │ ├── 1325. Delete Leaves With a Given Value.md │ ├── 2096. Step-By-Step Directions From a Binary Tree Node to Another.md │ ├── 2196. Create Binary Tree From Descriptions.md │ ├── 1166. Design File System.md │ ├── 291. Ternary Expression Tree.md │ └── 588. Design In-Memory File System.md └── Recursion │ └── 679. 24 Game.md ├── Trie └── TrieNode.java ├── .gitignore ├── OOD ├── StudentComparators.java └── Student.java ├── RainbowSortIII.java ├── ReverseNodesInKGroup.java ├── XorGreaterThanAndPair.java ├── LICENSE ├── NestedListWeightSum.java ├── Tree ├── FlattenBinaryTreeToString.java ├── BinaryTreeDiameter.java ├── AllLeafNodesAndPathMax.java ├── DistanceOfTwoNodesInBST.java ├── VerticalListOfBinaryTree.java ├── DistanceOfTwoNodesInBinaryTree.java ├── LongestAscendingPathBinaryTree.java └── SortedListToBinarySearchTree.java ├── MinGlassesToPourWater.java ├── InsertionSort.java ├── MaxWaterTrappedI.java ├── KeepDistanceForIdenticalElements.java ├── InsertionSortLinkedList.java ├── CuttingWood.java ├── LongestPalindromicSubstring.java ├── EvaluateReversePolishNotation.java ├── LongestCommonSubsequence.java ├── MergeKSortedArray.java ├── LargestSubMatrixSum.java ├── SortWithTwoStacks.java ├── CanIWin.java ├── SortInSpecifiedOrder.java ├── WordSearch.java ├── FactorCombinations.java ├── TotalOccurrence.java ├── AllValidPermutationsOfParenthesesII.java ├── AllPermutationsOfSubsets.java ├── QuickSortLinkedList.java ├── RotateMatrix.java ├── AllAnagrams.java ├── AllValidPermutationsOfParenthesesIII.java ├── RotateListbyKplaces.java ├── test ├── CompressTest.java └── utilTest │ └── HeapTest.java ├── SelectionSortLinkedList.java ├── SearchInSortedMatrixII.java ├── util └── Trie.java ├── RestoreIPAddresses.java ├── SortNumbersInThreeStacks.java └── FlipGameII.java /README.md: -------------------------------------------------------------------------------- 1 | # Algorithms Practices in Java 2 | -------------------------------------------------------------------------------- /Solutions/Images/7桥问题.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/7桥问题.png -------------------------------------------------------------------------------- /Solutions/Images/All Anagrams1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/All Anagrams1.png -------------------------------------------------------------------------------- /Solutions/Images/Bit_XOR_Equal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bit_XOR_Equal.png -------------------------------------------------------------------------------- /Solutions/Images/Flights_Bug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Flights_Bug.png -------------------------------------------------------------------------------- /Solutions/Images/negative_edge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/negative_edge.png -------------------------------------------------------------------------------- /Solutions/Images/Bit_ALL_ON_1_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bit_ALL_ON_1_9.png -------------------------------------------------------------------------------- /Solutions/Images/Bit_XOR_Equal2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bit_XOR_Equal2.png -------------------------------------------------------------------------------- /Solutions/Images/Bit_XOR_Equal3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bit_XOR_Equal3.png -------------------------------------------------------------------------------- /Solutions/Images/Bit_XOR_Equal4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bit_XOR_Equal4.png -------------------------------------------------------------------------------- /Solutions/Images/Bit_XOR_Equal5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bit_XOR_Equal5.png -------------------------------------------------------------------------------- /Solutions/Images/Bit_XOR_Equal6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bit_XOR_Equal6.png -------------------------------------------------------------------------------- /Solutions/Images/negative_weight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/negative_weight.png -------------------------------------------------------------------------------- /Solutions/Images/BellmanFord_demo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/BellmanFord_demo1.png -------------------------------------------------------------------------------- /Solutions/Images/BellmanFord_demo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/BellmanFord_demo2.png -------------------------------------------------------------------------------- /Solutions/Images/BellmanFord_demo3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/BellmanFord_demo3.png -------------------------------------------------------------------------------- /Solutions/Images/BellmanFord_demo4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/BellmanFord_demo4.png -------------------------------------------------------------------------------- /Solutions/Images/BellmanFord_demo5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/BellmanFord_demo5.png -------------------------------------------------------------------------------- /Solutions/Images/Bipartite_Example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bipartite_Example1.png -------------------------------------------------------------------------------- /Solutions/Images/Flights_NoResult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Flights_NoResult.png -------------------------------------------------------------------------------- /Solutions/Images/Heapify_Analysis1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Heapify_Analysis1.png -------------------------------------------------------------------------------- /Solutions/Images/Bipartite_Example1_BFS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bipartite_Example1_BFS.png -------------------------------------------------------------------------------- /Solutions/Images/Bipartite_Example1_DFS.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bipartite_Example1_DFS.jpeg -------------------------------------------------------------------------------- /Solutions/Images/Bipartite_Example2_BFS.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bipartite_Example2_BFS.jpeg -------------------------------------------------------------------------------- /Solutions/Images/Bipartite_Example2_DFS.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Bipartite_Example2_DFS.jpeg -------------------------------------------------------------------------------- /Solutions/Images/Flights_13Edges_Example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/Flights_13Edges_Example.png -------------------------------------------------------------------------------- /Solutions/Images/622_Design_Circular_Queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/622_Design_Circular_Queue.png -------------------------------------------------------------------------------- /Solutions/Images/641_Design_Circular_Deque.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/641_Design_Circular_Deque.png -------------------------------------------------------------------------------- /Solutions/Images/936_Stamping_The_Sequence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/936_Stamping_The_Sequence.png -------------------------------------------------------------------------------- /Solutions/Images/406-Diagonal-Sum-of-a-Binary-Tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/406-Diagonal-Sum-of-a-Binary-Tree.png -------------------------------------------------------------------------------- /Solutions/Images/HeapifyVSOfferAndPercolateUp_TC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/byegates/Algorithms/HEAD/Solutions/Images/HeapifyVSOfferAndPercolateUp_TC.png -------------------------------------------------------------------------------- /Trie/TrieNode.java: -------------------------------------------------------------------------------- 1 | package Trie; 2 | 3 | public class TrieNode { 4 | public TrieNode[] children = new TrieNode[26]; 5 | public boolean isWord; 6 | int count; 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # user add 26 | .idea/ 27 | out/ 28 | .DS_Store 29 | -------------------------------------------------------------------------------- /Solutions/BinarySearch.md: -------------------------------------------------------------------------------- 1 | # BinarySearch 2 | ## Boundary Discussion 3 | ### What causes dead loop? 4 | ## Classical 5 | ### 14. Classical Binary Search 6 | ```java 7 | public class Solution { 8 | public int binarySearch(int[] a, int t) { 9 | int l = 0, r = a.length - 1; 10 | while ( l <= r) { 11 | int m = l + (r - l) / 2; 12 | if (a[m] == t) return m; 13 | else if (a[m] < t) l = m + 1; 14 | else r = m - 1; 15 | } 16 | return -1; 17 | } 18 | } 19 | ``` -------------------------------------------------------------------------------- /Solutions/String and Array/560. Subarray Sum Equals K.md: -------------------------------------------------------------------------------- 1 | # [560. Subarray Sum Equals K](https://leetcode.com/problems/subarray-sum-equals-k/) 2 | 3 | ## prefix sum map 4 | TC: O(n), SC: O(n) 5 | ```java 6 | class Solution { 7 | public int subarraySum(int[] a, int k) { 8 | Map map = new HashMap<>(); 9 | int res = 0, sum = 0; 10 | map.put(0, 1); // init if the sum starts from index 0 11 | 12 | for (int x : a) { 13 | sum += x; 14 | res += map.getOrDefault(sum - k, 0); 15 | map.put(sum, map.getOrDefault(sum, 0) + 1); 16 | } 17 | 18 | return res; 19 | } 20 | } 21 | ``` -------------------------------------------------------------------------------- /Solutions/Misc/56. Merge Intervals.md: -------------------------------------------------------------------------------- 1 | # [56. Merge Intervals](https://leetcode.com/problems/merge-intervals/) 2 | 3 | ## In place 4 | TC: O(nlogn), SC: O(1) 5 | ```java 6 | class Solution { 7 | public int[][] merge(int[][] intervals) { 8 | Arrays.sort(intervals, (a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]); 9 | 10 | int keep = 0; 11 | for (int i = 1; i < intervals.length; i++) { 12 | int[] cur = intervals[i]; 13 | int[] pre = intervals[keep]; 14 | if (cur[1] <= pre[1]) continue; 15 | if (cur[0] <= pre[1]) pre[1] = cur[1]; 16 | else intervals[++keep] = intervals[i]; 17 | } 18 | 19 | return Arrays.copyOf(intervals, keep+1); 20 | } 21 | } 22 | ``` -------------------------------------------------------------------------------- /OOD/StudentComparators.java: -------------------------------------------------------------------------------- 1 | package OOD; 2 | 3 | import java.util.Comparator; 4 | import java.util.function.BiFunction; 5 | public enum StudentComparators implements Comparator { 6 | ID((s1, s2) -> Integer.compare(s1.id(), s2.id())), 7 | NAME((s1, s2) -> s1.name().compareTo(s2.name())), 8 | MATH((s1, s2) -> Integer.compare(s1.math(), s2.math())), 9 | PE((s1, s2) -> s1.pe().compareTo(s2.pe())), 10 | EN((s1, s2) -> s1.en().compareTo(s2.en())), 11 | ; 12 | 13 | private final BiFunction func; 14 | 15 | StudentComparators(BiFunction func) { 16 | this.func = func; 17 | } 18 | 19 | @Override 20 | public int compare(Student o1, Student o2) { 21 | return func.apply(o1, o2); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Solutions/String and Array/325. Maximum Size Subarray Sum Equals k.md: -------------------------------------------------------------------------------- 1 | # [325. Maximum Size Subarray Sum Equals k](https://leetcode.com/problems/maximum-size-subarray-sum-equals-k/) 2 | 3 | ## prefix sum in map 4 | Will add explanation later 5 | TC/SC: O(n) 6 | ```java 7 | class Solution { 8 | public int maxSubArrayLen(int[] a, int k) { 9 | Map map = new HashMap<>(); 10 | int longest = 0, sum = 0, n = a.length, len; 11 | map.put(0, -1); 12 | 13 | for (int i = 0; i < n; i++) { 14 | sum += a[i]; 15 | int start = map.getOrDefault(sum - k, -2); 16 | if (start != -2 && (len = i - start) > longest) longest = len; 17 | map.putIfAbsent(sum, i); 18 | } 19 | 20 | return longest; 21 | } 22 | } 23 | ``` -------------------------------------------------------------------------------- /Solutions/DP/1824. Minimum Sideway Jumps.md: -------------------------------------------------------------------------------- 1 | # [1824. Minimum Sideway Jumps](https://leetcode.com/problems/minimum-sideway-jumps/description/) 2 | ## 1d DP, 38ms, 96.36% 3 |
 4 | TC: O(3*n) => O(n)
 5 | SC: O(3) => O(1)
 6 | 
7 | ```java 8 | class Solution { 9 | public int minSideJumps(int[] obstacles) { 10 | int[] dp = new int[] {1, 0, 1}; // frog start at middle lane 11 | 12 | for (int x : obstacles) { 13 | if (x-- > 0) dp[x] = 1_000_000_000; // if there's an obstacle, then this lane is not reachable at this point 14 | for (int j = 0; j < 3; j++) 15 | if (j != x) 16 | dp[j] = Math.min(dp[j], Math.min(dp[(j+1)%3], dp[(j+2)%3])+1); 17 | } 18 | 19 | return Math.min(dp[0], Math.min(dp[1], dp[2])); 20 | } 21 | } 22 | ``` -------------------------------------------------------------------------------- /RainbowSortIII.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class RainbowSortIII { 4 | public int[] rainbowSortIII(int[] a, int k) { 5 | int l = 0, r = a.length - 1; 6 | for (int min = 1; min < k; min++, k--) 7 | for (int i = l; i <= r;) 8 | if (a[i] == min) swap(a, i++, l++); 9 | else if (a[r] == k) r--; 10 | else if (a[i] == k) swap(a, i, r--); 11 | else i++; 12 | 13 | return a; 14 | } 15 | 16 | private void swap(int[] a, int i, int j) { 17 | int tmp = a[i]; 18 | a[i] = a[j]; 19 | a[j] = tmp; 20 | } 21 | 22 | public static void main(String[] args) { 23 | RainbowSortIII sol = new RainbowSortIII(); 24 | System.out.println(Arrays.toString(sol.rainbowSortIII(new int[]{1, 3, 4, 2, 5, 2, 1}, 5))); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Solutions/DP/2321. Maximum Score Of Spliced Array.md: -------------------------------------------------------------------------------- 1 | # [2321. Maximum Score Of Spliced Array](https://leetcode.com/problems/maximum-score-of-spliced-array/) 2 | 3 | ## TC: O(n), SC: O(1) 3ms, 99.64% 4 | longest sub array diff sub, either from a1 to a2, or a2 to a1 5 | ```java 6 | class Solution { 7 | public int maximumsSplicedArray(int[] a1, int[] a2) { 8 | int sum1 = 0, sum2 = 0, n = a1.length, c1 = 0, c2 = 0, max1 = 0, max2 = 0; 9 | for (int x : a1) sum1 += x; 10 | for (int x : a2) sum2 += x; 11 | 12 | for (int i = 0; i < n; i++) { 13 | int diff = a1[i] - a2[i]; 14 | c1 += diff; 15 | c2 -= diff; 16 | if (c1 > 0) max1 = Math.max(c1, max1); 17 | else c1 = 0; 18 | if (c2 > 0) max2 = Math.max(c2, max2); 19 | else c2 = 0; 20 | } 21 | 22 | return Math.max(sum1 + max2, sum2 + max1); 23 | } 24 | } 25 | ``` -------------------------------------------------------------------------------- /Solutions/DP/894. All Possible Full Binary Trees.md: -------------------------------------------------------------------------------- 1 | # [894. All Possible Full Binary Trees](https://leetcode.com/problems/all-possible-full-binary-trees/) 2 | 3 | ## 1ms, 100% 4 | ```java 5 | class Solution { 6 | List[] cache = new ArrayList[21]; 7 | public List allPossibleFBT(int n) { 8 | List res = new ArrayList<>(); 9 | if (n % 2 == 0) return res; 10 | if (n == 1) { 11 | res.add(new TreeNode(0)); 12 | return res; 13 | } 14 | if (cache[n] != null) return cache[n]; 15 | 16 | for (int i = 1; i < n-1; i += 2) { 17 | List l = allPossibleFBT(i); 18 | List r = allPossibleFBT(n-1-i); 19 | 20 | for (TreeNode ln : l) for (TreeNode rn : r) 21 | res.add(new TreeNode(0, ln, rn)); 22 | } 23 | return cache[n] = res; 24 | } 25 | } 26 | ``` -------------------------------------------------------------------------------- /ReverseNodesInKGroup.java: -------------------------------------------------------------------------------- 1 | import util.ListNode; 2 | 3 | public class ReverseNodesInKGroup { 4 | // solution 1, count first 5 | public ListNode reverseKGroup(ListNode head, int k) { 6 | if(head == null || k == 1) return head; 7 | ListNode dummy = new ListNode(0); 8 | dummy.next = head; 9 | ListNode curr, prev = dummy , next; 10 | int count = 0; 11 | for (curr = dummy; curr.next != null; curr = curr.next) 12 | count++; 13 | 14 | for (; count >= k; count -= k){ 15 | curr = prev.next; 16 | next = curr.next; 17 | for(int i = 1; i < k; i++){ 18 | curr.next = next.next; 19 | next.next = prev.next; 20 | prev.next = next; 21 | next = curr.next; 22 | } 23 | prev = curr; 24 | } 25 | return dummy.next; 26 | } 27 | // solution 1 ends here 28 | } 29 | -------------------------------------------------------------------------------- /Solutions/DP/1140. Stone Game II.md: -------------------------------------------------------------------------------- 1 | # [1140. Stone Game II](https://leetcode.com/problems/stone-game-ii/) 2 | ## recursion + MEMO, 3ms, 100% 3 | TC: O(n^2), SC: O(n^2) 4 | ```java 5 | class Solution { 6 | public int stoneGameII(int[] piles) { 7 | int n = piles.length; 8 | int[] suf = new int[n]; // suffix sum 9 | suf[n-1] = piles[n-1]; 10 | for (int i = n - 2; i >= 0; i--) suf[i] = suf[i+1] + piles[i]; 11 | int[][] dp = new int[n][n]; 12 | return dfs(0, 1, suf, dp); 13 | } 14 | 15 | private int dfs(int idx, int m, int[] suf, int[][] dp) { 16 | int upper = 2 * m; 17 | if (idx + upper >= suf.length) return suf[idx]; 18 | if (dp[idx][m] != 0) return dp[idx][m]; 19 | 20 | int min = Integer.MAX_VALUE; 21 | for (int x = 1; x <= upper; x++) 22 | min = Math.min(min, dfs(idx + x, Math.max(x, m), suf, dp)); 23 | 24 | return dp[idx][m] = suf[idx] - min; 25 | } 26 | } 27 | ``` -------------------------------------------------------------------------------- /Solutions/String and Array/String Compress and Decompress.md: -------------------------------------------------------------------------------- 1 | # [394. Decode String](https://leetcode.com/problems/decode-string/) 2 | [LaiCode 621. Decompress String III](https://app.laicode.io/app/problem/621) 3 | TC: O(n), SC: O(# of '[') 4 | ```java 5 | class Solution { 6 | int idx; 7 | public String decodeString(String s) { 8 | idx = 0; 9 | return onePass(s).toString(); 10 | } 11 | 12 | public StringBuilder onePass(String s) { 13 | StringBuilder sb = new StringBuilder(); 14 | int num = 0; 15 | 16 | while (idx < s.length()) { 17 | char c = s.charAt(idx++); 18 | if (c >= '0' && c <= '9') num = c - '0' + num * 10; 19 | else if (c == '[') { 20 | StringBuilder sb0 = onePass(s); 21 | for ( ; num > 0; num--) sb.append(sb0); 22 | } else if (c == ']') break; 23 | else sb.append(c); 24 | } 25 | 26 | return sb; 27 | } 28 | } 29 | ``` -------------------------------------------------------------------------------- /Solutions/String and Array/2375. Construct Smallest Number From DI String.md: -------------------------------------------------------------------------------- 1 | # [2375. Construct Smallest Number From DI String](https://leetcode.com/problems/construct-smallest-number-from-di-string/) 2 | Almost the same as [484. Find Permutation](https://leetcode.com/problems/find-permutation/) 3 | ## 0ms 4 | TC/SC: O(n), n <= 10 5 | ```java 6 | class Solution { 7 | public String smallestNumber(String pat) { 8 | int n = pat.length(); 9 | int[] p = new int[n+1]; 10 | for (int i = 0; i < n; i++) if (pat.charAt(i) == 'D') p[i+1] = p[i] + 1; 11 | char[] a = new char[n+1]; 12 | 13 | int max = n+1, cur = max; 14 | for (int i = n; i >= 0; i--) { 15 | cur--; 16 | if (p[i] > 0) { 17 | a[i] = (char)(max - p[i] + '0'); 18 | } else { 19 | a[i] = (char)(max + '0'); 20 | max = cur; 21 | } 22 | } 23 | 24 | return new String(a); 25 | } 26 | } 27 | ``` -------------------------------------------------------------------------------- /Solutions/DP/2318. Number of Distinct Roll Sequences.md: -------------------------------------------------------------------------------- 1 | # [2318. Number of Distinct Roll Sequences](https://leetcode.com/problems/number-of-distinct-roll-sequences/) 2 | 3 | ## recursion + memo, 12ms, 99.9% 4 | TC: O(n), SC: O(490049) 5 | ```java 6 | class Solution { 7 | private static final int M = 1_000_000_007; 8 | private static final int[][][] memo = new int[10_001][7][7]; // declare here will make this much faster 9 | private static final int[][] dict = {{1, 2, 3, 4, 5, 6}, {2, 3, 4, 5, 6}, {1, 3, 5}, {1, 2, 4, 5}, {1, 3, 5}, {1, 2, 3, 4, 6}, {1, 5},}; 10 | 11 | public int distinctSequences(int n) { 12 | return dp(n, 0, 0); 13 | } 14 | 15 | private int dp(int n, int pre, int pre2) { 16 | if (n == 0) return 1; 17 | if (memo[n][pre][pre2] != 0) return memo[n][pre][pre2]; 18 | 19 | int res = 0; 20 | for (int x : dict[pre]) 21 | if (x != pre2) res = (res + dp(n - 1, x, pre)) % M; 22 | 23 | return memo[n][pre][pre2] = res; 24 | } 25 | } 26 | ``` -------------------------------------------------------------------------------- /Solutions/Misc/646. Maximum Length of Pair Chain.md: -------------------------------------------------------------------------------- 1 | # [646. Maximum Length of Pair Chain](https://leetcode.com/problems/maximum-length-of-pair-chain/) 2 | 3 | ## Greedy, 13ms, 83.36% 4 | ```java 5 | class Solution { 6 | public int findLongestChain(int[][] pairs) { 7 | Arrays.sort(pairs, (a, b) -> a[1] - b[1]); 8 | 9 | int res = 1, end = pairs[0][1]; 10 | for (var p : pairs) 11 | if (p[0] > end) { 12 | res++; 13 | end = p[1]; 14 | } 15 | 16 | return res; 17 | } 18 | } 19 | ``` 20 | ### slightly different 21 | ```java 22 | class Solution { 23 | public int findLongestChain(int[][] pairs) { 24 | Arrays.sort(pairs, (a, b) -> a[1] - b[1]); 25 | 26 | int res = 0, preEnd = -1001; // min val is -1000 27 | for (var p : pairs) 28 | if (p[0] > preEnd) { 29 | res++; 30 | preEnd = p[1]; 31 | } 32 | 33 | return res; 34 | } 35 | } 36 | ``` -------------------------------------------------------------------------------- /XorGreaterThanAndPair.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.List; 3 | 4 | public class XorGreaterThanAndPair { 5 | public long bigXorSum(List list) { 6 | int[] count = new int[31]; // for any positive integer, the msb index can be 0 to 30 in total 31 possibilities, (max int is 2^31 - 1) 7 | long res = 0; 8 | for (int i = 0; i < list.size(); i++) { 9 | int msb = 31 - Integer.numberOfLeadingZeros(list.get(i)); // msb stands for most significant digit, meaning the left most 1, and here we need its index 10 | res += i - count[msb]; // every round we make a pair with all previous numbers, but exclude numbers with same msb index 11 | count[msb]++; 12 | } 13 | return res; 14 | } 15 | 16 | public static void main(String[] args) { 17 | XorGreaterThanAndPair sol = new XorGreaterThanAndPair(); 18 | System.out.println(sol.bigXorSum(Arrays.asList(4, 3, 5, 2))); // 4 19 | System.out.println(sol.bigXorSum(Arrays.asList(4, 3, 5, 2, 1))); // 8 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 WLY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Solutions/DP/1771. Maximize Palindrome Length From Subsequences.md: -------------------------------------------------------------------------------- 1 | # [1771. Maximize Palindrome Length From Subsequences](https://leetcode.com/problems/maximize-palindrome-length-from-subsequences/) 2 | 3 | ## TC/SC n^2, almost the same with 516 4 | ```java 5 | class Solution { 6 | int[][] dp; 7 | public int longestPalindrome(String w1, String w2) { 8 | longestPalindromeSubseq(w1+w2); 9 | int res = 0, n1 = w1.length(); 10 | for (int i = 0; i < n1; i++) for (int j = 0; j < w2.length(); j++) 11 | if (w1.charAt(i) == w2.charAt(j)) res = Math.max(res, dp[i+1][j+n1-1] + 2); 12 | 13 | return res; 14 | } 15 | // 516 logic 16 | public int longestPalindromeSubseq(String s) { 17 | int n = s.length(); 18 | char[] a = s.toCharArray(); 19 | dp = new int[n][n]; 20 | for (int i = n-1; i >= 0; i--) for (int j = i; j < n; j++) { 21 | if (i == j) dp[i][j] = 1; 22 | else if (a[i] == a[j]) dp[i][j] = dp[i+1][j-1] +2; 23 | else dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]); 24 | } 25 | return dp[0][n-1]; 26 | } 27 | } 28 | ``` -------------------------------------------------------------------------------- /Solutions/DP/2312. Selling Pieces of Wood.md: -------------------------------------------------------------------------------- 1 | # [2312. Selling Pieces of Wood](https://leetcode.com/problems/selling-pieces-of-wood/) 2 | 3 | ## TC: O(mmn + mnn), O(mn) 4 | ```java 5 | class Solution { 6 | public long sellingWood(int m, int n, int[][] prices) { 7 | int[][] dp = new int[m+1][n+1]; 8 | 9 | for (var p : prices) dp[p[0]][p[1]] = p[2]; 10 | 11 | for (int w = 1; w <= m; w++) for (int h = 1; h <= n; h++) { 12 | for (int a = 1; a <= w / 2; a++) dp[w][h] = Math.max(dp[w][h], dp[a][h] + dp[w-a][h]); 13 | for (int a = 1; a <= h / 2; a++) dp[w][h] = Math.max(dp[w][h], dp[w][a] + dp[w][h-a]); 14 | } 15 | 16 | return dp[m][n]; 17 | } 18 | } 19 | ``` 20 |
21 | for Input:
22 | 3
23 | 5
24 | [[1,4,2],[2,2,7],[2,1,3]]
25 | 
26 | What DP table looks like:
27 | [ 0,  0,  0,  0,  0,  0]
28 | [ 0,  0,  0,  0,  2,  2]
29 | [ 0,  3,  7, 10, 14, 17]
30 | [ 0,  3,  7, 10, 16, 19]
31 | 
32 | For input:
33 | 4
34 | 6
35 | [[3,2,10],[1,4,2],[4,1,3]]
36 | What DP table looks like:
37 | [ 0,  0,  0,  0,  0,  0,  0]
38 | [ 0,  0,  0,  0,  2,  2,  2]
39 | [ 0,  0,  0,  0,  4,  4,  4]
40 | [ 0,  0, 10, 10, 20, 20, 30]
41 | [ 0,  3, 10, 13, 22, 25, 32]
42 | 
-------------------------------------------------------------------------------- /NestedListWeightSum.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given a nested list of integers represented by a string without blank, 3 | parse the string and return the sum of all integers in the list weighted by their depth. 4 | 5 | Each element is either an integer, or a list -- whose elements may also be integers or other lists. 6 | 7 | Example 1: 8 | Given the list "[[1,1],2,[1,1]]", return 10. (four 1's at depth 2, one 2 at depth 1) 9 | 10 | Example 2: 11 | Given the list "[1,[4,[6]]]", return 27. (one 1 at depth 1, one 4 at depth 2, and one 6 at depth 3; 1 + 4*2 + 6*3 = 27) 12 | */ 13 | public class NestedListWeightSum { 14 | public int depthSum(String s) { // TC: O(n), SC:O(1) 15 | int lvl = 0, sum = 0, curNumber = 0, sign = 1; 16 | for (int i = 0; i < s.length(); i++) { 17 | char c = s.charAt(i); 18 | if (c == '[') lvl++; 19 | else if (c == ']' || c == ',') { 20 | sum += curNumber * lvl * sign; 21 | curNumber = 0; // reset 22 | sign = 1; // reset 23 | if (c == ']') lvl--; 24 | } else if (c == '-') sign = -1; 25 | else curNumber = curNumber * 10 + c - '0'; // isNumeric 26 | } 27 | return sum; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Solutions/DP/312. Burst Balloons.md: -------------------------------------------------------------------------------- 1 | # [312. Burst Balloons](https://leetcode.com/problems/burst-balloons/) 2 | 3 | ## DP, TC: O(n^3), SC: O(n^2), 57 ms, 87.52% 4 | Do it backwards, check and calc which balloon get burst last 5 | ```java 6 | class Solution { 7 | public int maxCoins(int[] nums) { 8 | int n = nums.length + 2; 9 | int [] a = new int[n]; 10 | for (int i = 0; i < n-2; i++) a[i+1] = nums[i]; 11 | a[0] = a[n-1] = 1; // fill original array's left and right with 1 to handle corner case 12 | int[][] dp = new int[n][n]; // dp[i][j]: max coins burst balloons between [i, j] (inclusive) 13 | 14 | // filling the dp table vertically from i==j diagonal up to the top 15 | for (int len = 0; len < n-2; len++) { 16 | for (int i = 1; i + len < n - 1; i++) { 17 | int j = i + len; 18 | for (int k = i; k <= j; k++) { 19 | dp[i][j] = Math.max(dp[i][j], dp[i][k-1] + a[i-1] * a[k] * a[j + 1] + dp[k+1][j]); 20 | } // when i == j == k, dp[i][k-1] and dp[k+1][j] is in the lower half of dp which is never filled, so they'll be 0 (defaulted), and that's what we want 21 | } 22 | } 23 | 24 | return dp[1][n-2]; 25 | } 26 | } 27 | ``` -------------------------------------------------------------------------------- /Tree/FlattenBinaryTreeToString.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | 3 | import util.TreeNode; 4 | 5 | public class FlattenBinaryTreeToString { 6 | public String flattenBinaryTree(TreeNode root) { // TC: O(n), SC: O(height) 7 | StringBuilder sb = new StringBuilder(); 8 | dfs(root, sb); 9 | return sb.toString(); 10 | } 11 | 12 | private void dfs(TreeNode root, StringBuilder sb) { // preOrder/Depth First Search to traversal the whole tree 13 | if (root == null) return; 14 | sb.append(root.key); 15 | if (root.left != null) { 16 | sb.append('('); 17 | dfs(root.left, sb); 18 | sb.append(')'); 19 | } 20 | if (root.right != null) { 21 | if (root.left == null) sb.append("()"); 22 | sb.append("("); 23 | dfs(root.right, sb); 24 | sb.append(')'); 25 | } 26 | } 27 | 28 | public static void main(String[] args) { 29 | FlattenBinaryTreeToString fbt = new FlattenBinaryTreeToString(); 30 | System.out.println(fbt.flattenBinaryTree(TreeNode.fromLevelOrder(new Integer[]{-6, 5, 10, 3}))); // -6(5(3))(10) 31 | System.out.println(fbt.flattenBinaryTree(TreeNode.fromLevelOrderSpecial(new String[]{"2","-7","#","5","10","4","3","#","-2","-1","-3"}))); // 2(-7(5(4(-1)(-3))(3))(10()(-2))) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tree/BinaryTreeDiameter.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | 3 | import util.TreeNode; 4 | 5 | /* 6 | Given a binary tree in which each node contains an integer number. 7 | The diameter is defined as the longest distance from one leaf node to another leaf node. 8 | The distance is the number of nodes on the path. 9 | If there does not exist any such paths, return 0. 10 | Examples 11 | 5 12 | / \ 13 | 2 11 14 | / \ 15 | 6 14 16 | The diameter of this tree is 4 (2 → 5 → 11 → 14) 17 | */ 18 | public class BinaryTreeDiameter { 19 | int max = 0; 20 | public int diameter(TreeNode root) { 21 | dfs(root); 22 | return max; 23 | } 24 | 25 | private int dfs(TreeNode root) { // TC: O(n), SC: O(height) 26 | if (root == null) return 0; 27 | int left = dfs(root.left) + 1; 28 | int right = dfs(root.right) + 1; 29 | if (root.left != null && root.right != null) 30 | max = Math.max(max, left + right - 1); 31 | return Math.max(left, right); 32 | } 33 | 34 | public static void main(String[] args) { 35 | TreeNode root = TreeNode.fromLevelOrder(new Integer[]{1, 2, 6, 3, 4, null, null, 7, 8, 5, null, null, null, 9, null, 10}); 36 | BinaryTreeDiameter btd = new BinaryTreeDiameter(); 37 | System.out.println(btd.diameter(root)); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /MinGlassesToPourWater.java: -------------------------------------------------------------------------------- 1 | /* 2 | n glasses with capacity of 1, 2, 3 ... to n 3 | to pour k liters of water, what's the min number of glasses needed? 4 | All glasses used must be fully filled 5 | */ 6 | 7 | public class MinGlassesToPourWater { 8 | public int min(int n, int k) { 9 | if (k > n * (n + 1) / 2) return -1; 10 | int res = 0; 11 | 12 | while (k > 0) { 13 | if (n == 0) return -1; // all glasses used and k is still > 0, no solution 14 | k -= n--; // just pour the largest glass and removed that glass 15 | res++; 16 | if (k <= 0) break; // if k is less than 0, it can be poured into a smaller glass(which exists for sure) 17 | } 18 | return res; 19 | } 20 | 21 | public static void main(String[] args) { 22 | MinGlassesToPourWater mg = new MinGlassesToPourWater(); 23 | System.out.println(mg.min(4, 10) == 4); 24 | System.out.println(mg.min(5, 10) == 3); 25 | System.out.println(mg.min(6, 10) == 2); 26 | System.out.println(mg.min(7, 10) == 2); 27 | System.out.println(mg.min(8, 10) == 2); 28 | System.out.println(mg.min(9, 10) == 2); 29 | System.out.println(mg.min(10, 10) == 1); 30 | System.out.println(mg.min(5, 8) == 2); 31 | System.out.println(mg.min(1, 2) == -1); 32 | System.out.println(mg.min(10, 5) == 1); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Solutions/GraphSearch/1631. Path With Minimum Effort.md: -------------------------------------------------------------------------------- 1 | # [1631. Path With Minimum Effort](https://leetcode.com/problems/path-with-minimum-effort/) 2 | 3 | ## BFS2/Dijkstra (42 ms, 99.27%) 4 | TC: mn * log(mn) 5 | 6 | SC: mn 7 | ```java 8 | class Solution { 9 | private static final int[][] dirs = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; 10 | record Cell (int i, int j, int eff) {} 11 | public int minimumEffortPath(int[][] hh) { 12 | int m = hh.length, n = hh[0].length; 13 | int[][] effort = new int[m][n]; 14 | for (var row : effort) Arrays.fill(row, Integer.MAX_VALUE); 15 | 16 | PriorityQueue q = new PriorityQueue<>((a, b) -> (a.eff - b.eff)); 17 | q.offer(new Cell(0, 0, effort[0][0] = 0)); 18 | 19 | while (!q.isEmpty()) { 20 | Cell cur = q.poll(); 21 | if (cur.i == m - 1 && cur.j == n - 1) return cur.eff; 22 | 23 | for (var dir : dirs) { 24 | int i2 = cur.i + dir[0], j2 = cur.j + dir[1]; 25 | if (i2 < 0 || j2 < 0 || i2 >= m || j2 >= n) continue; 26 | int curMax = Math.max(Math.abs(hh[i2][j2] - hh[cur.i][cur.j]), cur.eff); 27 | 28 | if (curMax < effort[i2][j2]) 29 | q.offer(new Cell(i2, j2, effort[i2][j2] = curMax)); 30 | } 31 | } 32 | 33 | return -1; 34 | } 35 | } 36 | ``` -------------------------------------------------------------------------------- /Solutions/DP/474. Ones and Zeroes.md: -------------------------------------------------------------------------------- 1 | # [474. Ones and Zeroes](https://leetcode.com/problems/ones-and-zeroes/) 2 | 3 | ## 2d DP, 22ms, 97.17% 4 | Optimized from 3D dp 5 | ```java 6 | class Solution { 7 | record Pair(int a, int b) {} 8 | public int findMaxForm(String[] strs, int m, int n) { 9 | int l = strs.length; 10 | int[] ones = new int[l], zeros = new int[l]; 11 | prep(strs, ones, zeros); 12 | 13 | int[][] dp = new int[m+1][n+1]; 14 | 15 | for (int k = 0; k < l; k++) { // how many bags we take 16 | int cnt0 = zeros[k], cnt1 = ones[k]; 17 | for (int i = m; i >= cnt0; i--) { // i,j backwards as we need dp[i][j] from previous round 18 | for (int j = n; j >= cnt1; j--) { 19 | dp[i][j] = Math.max(dp[i][j], dp[i-cnt0][j-cnt1] + 1); 20 | } 21 | } 22 | } 23 | 24 | return dp[m][n]; 25 | } 26 | 27 | private void prep(String[] strs, int[] ones, int[] zeros) { 28 | for (int i = 0; i < strs.length; i++) { 29 | ones[i] = count1(strs[i]); 30 | zeros[i] = strs[i].length() - ones[i]; 31 | } 32 | } 33 | 34 | private int count1(String s) { 35 | int cnt = 0; 36 | for (int i = 0; i < s.length(); i++) 37 | if (s.charAt(i) == '1') 38 | cnt++; 39 | return cnt; 40 | } 41 | } 42 | ``` -------------------------------------------------------------------------------- /Solutions/Stack and Queue/622. Design Circular Queue.md: -------------------------------------------------------------------------------- 1 | # [622. Design Circular Queue](https://leetcode.com/problems/design-circular-queue/submissions/) 2 | 3 | ## 思路 4 | 1. head, tail两个指针表示头尾 5 | 2. size 表示队列内元素个数 6 | 3. 按照Java queue interface的统一标准, tail入队, head出队 7 | 4. offer(enQueue): ++tail 8 | 5. poll(deQueue): ++head 9 | 6. 因为只需要但方向进出, 初始值: tail = -1, head = 0 10 | 1. 第一次enQueue之后tail = head = 0, 这样直接Front() & Rear() 都能直接得到对应的值 11 | ### DEMO 12 | ![](../Images/622_Design_Circular_Queue.png) 13 | 14 | ### 3ms, 100% 15 | ```java 16 | class MyCircularQueue { 17 | private int tail, head, size, n; 18 | private final int[] a; 19 | public MyCircularQueue(int k) { 20 | a = new int[k]; 21 | tail = -1; 22 | n = k; 23 | } 24 | 25 | public boolean enQueue(int x) { 26 | if (size == n) return false; 27 | a[tail = ++tail % n] = x; 28 | size++; 29 | return true; 30 | } 31 | 32 | public boolean deQueue() { 33 | if (size == 0) return false; 34 | head = ++head % n; 35 | size--; 36 | return true; 37 | } 38 | 39 | public int Front() { 40 | return size == 0 ? -1 : a[head]; 41 | } 42 | 43 | public int Rear() { 44 | return size == 0 ? -1 : a[tail]; 45 | } 46 | 47 | public boolean isEmpty() { 48 | return size == 0; 49 | } 50 | 51 | public boolean isFull() { 52 | return size == n; 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /Solutions/GraphSearch/847. Shortest Path Visiting All Nodes.md: -------------------------------------------------------------------------------- 1 | # [847. Shortest Path Visiting All Nodes](https://leetcode.com/problems/shortest-path-visiting-all-nodes/) 2 |
 3 | Standard BFS
 4 | # of Nodes: 2^n * n
 5 | TC: 2^n*n^2 (for every of 2^n * n nodes, there's n edges)
 6 | SC: 2^n*n
 7 | 
8 | ## 10ms, 93.85% 9 | ```java 10 | class Solution { 11 | private static int ALL_NODES; 12 | record Node (int mask, int i) {} 13 | public int shortestPathLength(int[][] g) { 14 | int n = g.length; 15 | ALL_NODES = (1 << n) - 1; 16 | 17 | Queue q = new ArrayDeque<>(); 18 | boolean[][] visited = new boolean[1 << n][n]; 19 | for (int i = 0; i < n; i++) { 20 | int mask = 1 << i; 21 | q.offer(new Node(mask, i)); 22 | visited[mask][i] = true; 23 | } 24 | 25 | for (int res = 0; !q.isEmpty(); res++) { 26 | for (int sz = q.size(); sz-- > 0;) { 27 | Node cur = q.poll(); 28 | if (cur.mask == ALL_NODES) return res; 29 | 30 | for (int next : g[cur.i]) { 31 | int newMask = cur.mask | 1 << next; 32 | if (visited[newMask][next]) continue; 33 | visited[newMask][next] = true; 34 | q.offer(new Node(newMask, next)); 35 | } 36 | } 37 | } 38 | 39 | return -1; 40 | } 41 | } 42 | ``` -------------------------------------------------------------------------------- /InsertionSort.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | public class InsertionSort { 4 | // Insertion sort with binary search to decide where to insert 5 | public int[] sort(int[] a) { 6 | if (a == null) return null; 7 | for (int j = 1; j < a.length; j++) 8 | for (int i = 0; i < j; i++) 9 | insertAtFirstLarger(a, firstLarger(a, j - 1, a[j]), j); 10 | 11 | return a; 12 | } 13 | 14 | private void insertAtFirstLarger(int[] a, int i, int j) { // insert j to i; 15 | int val = a[j]; 16 | for (int k = j; k > i; k--) a[k] = a[k - 1]; 17 | a[i] = val; 18 | } 19 | 20 | private int firstLarger(int[] a, int r, int t) { 21 | int l = 0; 22 | while (l < r) { 23 | int m = l + (r - l) / 2; 24 | if (a[m] > t) r = m; 25 | else l = m + 1; 26 | } 27 | return a[l] > t ? l : l + 1; 28 | } 29 | 30 | public static void main(String[] args) { 31 | InsertionSort sol = new InsertionSort(); 32 | System.out.println(Arrays.toString(sol.sort(new int[]{528, 494, 585, 535, 300, 467, 76, 361, 264, 675, 434, 608, 588, 726, 48, 832, 288, 731, 405, 125, 629, 806, 680, 196, 103, 773, 939, 876, 52, 360, 551, 546, 571, 893, 256, 324, 326, 89, 709, 303, 455}))); 33 | } 34 | 35 | } 36 | // =if(ISNUMBER(index(split(C18,"."),0,1)), HYPERLINK(CONCAT("https://app.laicode.io/app/problem/",index(split(C18,"."),0,1)),index(split(C18,"."),0,1)),"格式不对") 37 | -------------------------------------------------------------------------------- /Tree/AllLeafNodesAndPathMax.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | 3 | import util.TreeNode; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /* 9 | Given a binary tree, return all leaf nodes and path max from root to each leaf nodes 10 | */ 11 | public class AllLeafNodesAndPathMax { 12 | 13 | public static void main(String[] args) { 14 | AllLeafNodesAndPathMax sol = new AllLeafNodesAndPathMax(); 15 | for (TreeNode root : TreeNode.sampleTrees()) 16 | System.out.printf("%s\n%s\n", root, sol.search(root)); 17 | } 18 | 19 | static class Result { 20 | TreeNode leaf; 21 | int pathMax; 22 | Result(TreeNode leaf, int pathMax) { 23 | this.leaf = leaf; 24 | this.pathMax = pathMax; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return String.format("(%d, %d)", leaf.key, pathMax); 30 | } 31 | } 32 | public List search(TreeNode root) { 33 | List res = new ArrayList<>(); 34 | if (root != null) dfs(root, res, root.key); 35 | return res; 36 | } 37 | 38 | private void dfs(TreeNode root, List res, int max) { 39 | if (root.left == null && root.right == null) res.add(new Result(root, max)); 40 | if (root.left != null) dfs(root.left , res, Math.max(root.left.key , max)); 41 | if (root.right != null) dfs(root.right, res, Math.max(root.right.key, max)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Solutions/Monotonic Stack/862. Shortest Subarray with Sum at Least K.md: -------------------------------------------------------------------------------- 1 | # [862. Shortest Subarray with Sum at Least K](https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/) 2 | 3 | ## use array as deque, 20ms, 100% 4 | ```java 5 | class Solution { 6 | public int shortestSubarray(int[] a, int k) { 7 | int n = a.length, res = n+1, l = 0, r = -1; // l and r is left and right side of deque 8 | long[] p = new long[n+1]; // get prefix sum 9 | for (int i = 0; i < n; i++) p[i+1] = p[i] + a[i]; 10 | 11 | // we need mono increasing stack(Deque) 12 | int[] s = new int[n+1]; 13 | for (int i = 0; i <= n; s[++r] = i++) { 14 | while (r >= l && p[i] <= p[s[r]]) r--; // p[i] needs to be increasing 15 | while (l <= r && p[i] - p[s[l]] >= k) 16 | res = Math.min(res, i - s[l++]); 17 | } 18 | 19 | return res == n+1 ? -1 : res; 20 | } 21 | } 22 | ``` 23 | ### Sample cases 24 |
25 | Rule #1: for left boundary, once used, never needed again
26 | 
27 | k = 3
28 |  val:   1 5 -4 1 1 1 1 1
29 | psum: 0 1 6  2 3 4 5 6 7
30 |         l
31 |           r
32 | 
33 | Rule #2, we only want psum to increase
34 | k = 7
35 |  val:   1 5 -4 0 1 1 1 1 1
36 | psum: 0 1 6  2 2 3 4 5 6 7
37 | if 6 can be left bound, 2 - 6 after it must be better left bound
38 | Besides, if its not mono increasing, it's hard for us to shrink the window
39 | 
40 | k = 3
41 |  val:   2 -1 2
42 | psum: 0 2  1 3
43 | 
-------------------------------------------------------------------------------- /MaxWaterTrappedI.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given a non-negative integer array representing the heights of a list of adjacent bars. Suppose each bar has a width of 1. Find the largest amount of water that can be trapped in the histogram. 3 | 4 | Assumptions 5 | The given array is not null 6 | Examples 7 | { 2, 1, 3, 2, 4 }, the amount of water can be trapped is 1 + 1 = 2 (at index 1, 1 unit of water can be trapped and index 3, 1 unit of water can be trapped) 8 | 9 | */ 10 | 11 | public class MaxWaterTrappedI { 12 | 13 | public int maxTrapped(int[] arr) { // TC: O(n), SC: O(1) 14 | int res = 0, n = arr.length; 15 | if (n == 0) return res; 16 | 17 | int lmax = arr[0], rmax = arr[n - 1]; 18 | for (int l = 1, r = n - 2; l <= r;) { 19 | if (lmax < rmax) { 20 | if (arr[l] > lmax) lmax = arr[l]; 21 | res += Math.max(0, lmax - arr[l++]); 22 | } else { 23 | if (arr[r] > rmax) rmax = arr[r]; 24 | res += Math.max(0, rmax - arr[r--]); 25 | } 26 | } 27 | return res; 28 | } 29 | 30 | public static void main(String[] args) { 31 | MaxWaterTrappedI mwt1 = new MaxWaterTrappedI(); 32 | System.out.println(mwt1.maxTrapped(new int[]{5,3,2,1,4,6})); // 10 33 | System.out.println(mwt1.maxTrapped(new int[]{3, 2, 1})); // 0 34 | System.out.println(mwt1.maxTrapped(new int[]{1,2,3,4,4,4,5})); // 0 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Solutions/Tree/2246. Longest Path With Different Adjacent Characters.md: -------------------------------------------------------------------------------- 1 | # [2246. Longest Path With Different Adjacent Characters](https://leetcode.com/problems/longest-path-with-different-adjacent-characters/) 2 | 3 | ## Tree Traversal like max path sum 4 | TC: O(n), SC: O(height) 5 | ```java 6 | class Solution { 7 | int res; 8 | public int longestPath(int[] parent, String s) { 9 | res = 0; 10 | int n = parent.length; 11 | char[] a = s.toCharArray(); 12 | // init and build the tree 13 | List[] tree = new List[n]; 14 | for (int i = 0; i < n; i++) tree[i] = new ArrayList<>(); 15 | for(int i = 1; i < n; i++) tree[parent[i]].add(i); 16 | 17 | dfs(tree, 0, a); 18 | 19 | return res; 20 | } 21 | 22 | public int dfs(List[] tree, int i, char[] a) { 23 | int max1 = 0, max2 = 0; 24 | for(int c : tree[i]) { 25 | int cur = dfs(tree, c, a); 26 | if(a[c] == a[i]) continue; 27 | if(cur > max1) { 28 | max2 = max1; 29 | max1 = cur; 30 | } else if (cur > max2) max2 = cur; 31 | } 32 | 33 | res = Math.max(res, 1 + max1 + max2); 34 | return 1 + max1; 35 | } 36 | } 37 | ``` 38 | ## [[Java] 15ms beats 100.01% time, 100% MEM Topological Sort 'climb back up'](https://leetcode.com/problems/longest-path-with-different-adjacent-characters/discuss/2508404/Java-15ms-beats-100.01-time-100-MEM-Topological-Sort) -------------------------------------------------------------------------------- /Solutions/Misc/715. Range Module.md: -------------------------------------------------------------------------------- 1 | # [715. Range Module](https://leetcode.com/problems/range-module/) 2 | ## TreeMap, 48ms, 94.29% 3 | ```java 4 | class RangeModule { 5 | TreeMap map = new TreeMap<>(); 6 | 7 | public RangeModule() {} 8 | 9 | public void addRange(int l, int r) { 10 | int newL = l, newR = r; 11 | Map.Entry e0 = map.floorEntry(l); 12 | Map.Entry e1 = map.floorEntry(r); 13 | if (e0 != null && e0.getValue() >= l) newL = e0.getKey(); 14 | if (e1 != null && e1.getValue() >= l) newR = Math.max(r, e1.getValue()); 15 | map.subMap(l, true, r, true).clear(); // clear all overlap ranges, if any 16 | map.put(newL, newR); // add new range, may or may not be old ones 17 | } 18 | 19 | public boolean queryRange(int l, int r) { 20 | Map.Entry e = map.floorEntry(l); 21 | return e != null && e.getValue() >= r; 22 | } 23 | 24 | public void removeRange(int l, int r) { 25 | Map.Entry e0 = map.floorEntry(l); 26 | Map.Entry e1 = map.floorEntry(r); 27 | if (e0 != null && e0.getValue() > l) map.put(e0.getKey(), l); 28 | if (e1 != null && e1.getValue() > r) map.put(r, e1.getValue()); 29 | 30 | map.subMap(l, true, r, false).clear(); // clear all overlap ranges, if any 31 | } 32 | } 33 | ``` 34 | ## Segment Tree 35 | To add 36 | ```java 37 | class Solution { 38 | 39 | } 40 | ``` -------------------------------------------------------------------------------- /Solutions/DP/2262. Total Appeal of A String.md: -------------------------------------------------------------------------------- 1 | # [2262. Total Appeal of A String](https://leetcode.com/problems/total-appeal-of-a-string/) 2 | 3 | ## DP, TC/SC: O(n) 4 | dp definition, dp[i]: total appeal of all subarray ending at index i 5 | 6 | So what we return is the sum of dp table 7 | ```java 8 | class Solution { 9 | public long appealSum(String s) { 10 | int n = s.length(); 11 | long[] dp = new long[n]; 12 | int[] lastOccur = new int[26]; 13 | Arrays.fill(lastOccur, -1); 14 | long res = dp[0] = 1; 15 | lastOccur[s.charAt(0) - 'a'] = 0; // init first char as we start one index 1 16 | 17 | for (int i = 1; i < n; i++) { 18 | int idx = s.charAt(i) - 'a'; 19 | dp[i] = dp[i-1] + (i - lastOccur[idx]); 20 | res += dp[i]; 21 | lastOccur[idx] = i; 22 | } 23 | 24 | return res; 25 | } 26 | } 27 | ``` 28 | 29 | ## DP, TC: O(n), SC: O(1) 30 | ```java 31 | class Solution { 32 | public long appealSum(String s) { 33 | int n = s.length(); 34 | int[] lastOccur = new int[26]; 35 | Arrays.fill(lastOccur, -1); 36 | long res = 1, cur = 1; 37 | lastOccur[s.charAt(0) - 'a'] = 0; // init first char as we start one index 1 38 | 39 | for (int i = 1; i < n; i++) { 40 | int idx = s.charAt(i) - 'a'; 41 | res += (cur += i - lastOccur[idx]); 42 | lastOccur[idx] = i; 43 | } 44 | 45 | return res; 46 | } 47 | } 48 | ``` -------------------------------------------------------------------------------- /Solutions/GraphSearch/2497. Maximum Star Sum of a Graph.md: -------------------------------------------------------------------------------- 1 | # [2497. Maximum Star Sum of a Graph](https://leetcode.com/problems/maximum-star-sum-of-a-graph/description/) 2 | [Solution on Leetcode](https://leetcode.com/problems/maximum-star-sum-of-a-graph/solutions/2899105/java-adjacency-list-graph-priorityqueue-topk-easy-to-understand-50ms/?orderBy=most_votes) 3 | ## 4 |
 5 | TC: O(V+E)
 6 | SC: O(V+E+k)
 7 | 
8 | ```java 9 | class Solution { 10 | public int maxStarSum(int[] vals, int[][] edges, int k) { 11 | int n = vals.length; 12 | // create graph 13 | List[] g = new List[n]; 14 | for (int i = 0; i < n; i++) g[i] = new ArrayList<>(); 15 | for (var e : edges) { 16 | if (vals[e[1]] > 0) g[e[0]].add(vals[e[1]]); // we only need values of each node, and only positive values 17 | if (vals[e[0]] > 0) g[e[1]].add(vals[e[0]]); 18 | } 19 | 20 | int res = Integer.MIN_VALUE; 21 | for (int i = 0; i < n; i++) res = Math.max(res, topK(g[i], vals[i], k)); 22 | return res; 23 | } 24 | 25 | private int topK(List l, int res, int k) { // star sum is effectively topK positive sum 26 | Queue q = new PriorityQueue<>(); 27 | for (int x : l) { 28 | if (q.size() < k) q.offer(x); 29 | else if (x > q.peek()) { 30 | q.poll(); 31 | q.offer(x); 32 | } 33 | } 34 | 35 | while (!q.isEmpty()) res += q.poll(); 36 | 37 | return res; 38 | } 39 | } 40 | ``` -------------------------------------------------------------------------------- /Tree/DistanceOfTwoNodesInBST.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | 3 | import util.TreeNode; 4 | 5 | public class DistanceOfTwoNodesInBST { 6 | public int distanceBST(TreeNode root, int k1, int k2) { // TC: O(height) log(n)~n, SC: O(1) 7 | TreeNode lca = lca(root, Math.min(k1, k2), Math.max(k1, k2)); 8 | return distance(lca, k1) + distance(lca, k2); 9 | } 10 | 11 | private TreeNode lca(TreeNode root, int min, int max) { 12 | while (true) { 13 | if (root.key < min) root = root.right; 14 | else if (root.key > max) root = root.left; 15 | else return root; 16 | } 17 | } 18 | 19 | private int distance(TreeNode root, int k) { 20 | for (int depth = 0; ; depth++) { 21 | if (root.key == k) return depth; 22 | else if (root.key < k) root = root.right; 23 | else root = root.left; 24 | } 25 | } 26 | 27 | public static void main(String[] args) { 28 | DistanceOfTwoNodesInBST db = new DistanceOfTwoNodesInBST(); 29 | TreeNode root = TreeNode.fromLevelOrder(new Integer[]{4, 2, 6, 1, 3, 5, 7}); 30 | System.out.println(root); 31 | System.out.println(db.distanceBST(root, 1, 2)); // 1 32 | System.out.println(db.distanceBST(root, 1, 3)); // 2 33 | System.out.println(db.distanceBST(root, 1, 4)); // 2 34 | System.out.println(db.distanceBST(root, 1, 5)); // 4 35 | System.out.println(db.distanceBST(root, 1, 6)); // 3 36 | System.out.println(db.distanceBST(root, 1, 7)); // 4 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /KeepDistanceForIdenticalElements.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given an integer k, arrange the sequence of integers [1, 1, 2, 2, 3, 3, ...., k - 1, k - 1, k, k], such that the output integer array satisfy this condition: 3 | Between each two i's, they are exactly i integers (for example: between the two 1s, there is one number, between the two 2's there are two numbers). 4 | If there does not exist such sequence, return null. 5 | 6 | Assumptions: 7 | k is guaranteed to be > 0 8 | Examples: 9 | 10 | k = 3, The output = { 2, 3, 1, 2, 1, 3 }. 11 | */ 12 | 13 | import java.util.Arrays; 14 | 15 | public class KeepDistanceForIdenticalElements { 16 | public int[] keepDistance(int k) { // TC: O(n!), SC: O(n) 17 | int[] A = new int[2 * k]; 18 | return dfs(A, k) ? A : null; 19 | } 20 | 21 | private boolean dfs(int[] A, int k) { 22 | if (k == 0) return true; 23 | 24 | for (int i = 0; i < A.length - k - 1; i++) { 25 | if (A[i] != 0 || A[i + k + 1] != 0) continue; 26 | A[i] = k; 27 | A[i + k + 1] = k; 28 | if (dfs(A, k - 1)) return true; 29 | A[i] = 0; 30 | A[i + k + 1] = 0; 31 | } 32 | 33 | return false; 34 | } 35 | 36 | public static void main(String[] args) { 37 | KeepDistanceForIdenticalElements kd4ie = new KeepDistanceForIdenticalElements(); 38 | for (int i = 0; i < 13; i++) 39 | System.out.printf("%2d : %s\n",i , Arrays.toString(kd4ie.keepDistance(i))); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Solutions/Recursion/679. 24 Game.md: -------------------------------------------------------------------------------- 1 | # [679. 24 Game](https://leetcode.com/problems/24-game/) 2 | 3 | ## backtrack with swap 4 | TC: O(6^3) SC: O(3) 5 | 6 | ### 思路 7 | 所有的任意两两组合,选了做6种操作: 8 | 9 | x+y, x*y, x/y, x-y, y-x, y/x 10 | 11 | +和*没有顺序,/和-有顺序 12 | 13 | 可以用swap来De-Dup,用过的数字放到最后,然后iterate的时候每一层都提前一个位置结束 14 | ```java 15 | class Solution { 16 | public boolean judgePoint24(int[] cards) { 17 | double [] a = new double[] {cards[0], cards[1], cards[2], cards[3]}; 18 | return dfs(a, 4); 19 | } 20 | 21 | private boolean dfs(double[] a, int n) { 22 | // base case 23 | if (n == 1) return Math.abs(a[0] - 24.0) < .000001; 24 | 25 | // iterate over all options 26 | for (int i = 0; i < n - 1; i++) for (int j = i + 1; j < n; j++) { 27 | double x = a[i], y = a[j]; 28 | a[j] = a[n - 1]; // swap used value out 29 | a[i] = x + y; // calculated value is always at 1st index 30 | 31 | if (dfs(a, n - 1)) return true; 32 | a[i] = x * y; 33 | if (dfs(a, n - 1)) return true; 34 | a[i] = x / y; 35 | if (dfs(a, n - 1)) return true; 36 | a[i] = x - y; 37 | if (dfs(a, n - 1)) return true; 38 | a[i] = y / x; 39 | if (dfs(a, n - 1)) return true; 40 | a[i] = y - x; 41 | if (dfs(a, n - 1)) return true; 42 | 43 | a[i] = x; // recover x 44 | a[j] = y; // recover y 45 | } 46 | 47 | return false; 48 | } 49 | } 50 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/863. All Nodes Distance K in Binary Tree.md: -------------------------------------------------------------------------------- 1 | # [863. All Nodes Distance K in Binary Tree](https://leetcode.com/problems/all-nodes-distance-k-in-binary-tree/) 2 | 3 | ## Solution 1, standard BFS, create a map for parent nodes 4 | ```java 5 | class Solution { 6 | public List distanceK(TreeNode root, TreeNode target, int k) { 7 | Map parents = new HashMap<>(); 8 | dfs(root, null, parents); 9 | 10 | Queue q = new ArrayDeque<>(); 11 | Set set = new HashSet<>(); 12 | q.offer(target); 13 | set.add(target); 14 | 15 | List res = new ArrayList<>(); 16 | for (int step = 0; step <= k && !q.isEmpty(); step++) { 17 | for (int size = q.size(); size > 0; size--) { 18 | TreeNode cur = q.poll(); 19 | 20 | if (step == k) res.add(cur.val); 21 | 22 | if (cur.left != null && set.add(cur.left )) q.offer(cur.left ); 23 | if (cur.right != null && set.add(cur.right)) q.offer(cur.right); 24 | 25 | TreeNode parent = parents.get(cur); 26 | if (parent != null && set.add(parent)) q.offer(parent); 27 | } 28 | } 29 | 30 | return res; 31 | } 32 | 33 | private void dfs(TreeNode root, TreeNode parent, Map map) { 34 | if (root == null) return; 35 | map.put(root, parent); 36 | dfs(root.left , root, map); 37 | dfs(root.right, root, map); 38 | } 39 | } 40 | ``` 41 | -------------------------------------------------------------------------------- /InsertionSortLinkedList.java: -------------------------------------------------------------------------------- 1 | import util.ListNode; 2 | 3 | public class InsertionSortLinkedList { 4 | public ListNode insertionSort(ListNode head) { // TC: O(n^2), SC: O(n) 5 | if (head == null) return null; 6 | ListNode dummy = new ListNode(Integer.MIN_VALUE); 7 | dummy.next = head; 8 | 9 | for (ListNode s1 = head; s1.next != null;){ 10 | ListNode s2 = dummy; 11 | for (; s2 != s1; s2 = s2.next) { 12 | if (s2.next.value > s1.next.value) { 13 | // index 0 1 2 3 14 | // dummy 5 4 3 2 15 | // s1 16 | // s2 17 | ListNode temp = s1.next; // temp = 4 18 | s1.next = temp.next; // 5 --> 3 19 | temp.next = s2.next; // 4 --> 5 20 | s2.next = temp; // s2 --> 4 21 | break; 22 | // index 0 1 2 3 23 | // dummy 4 5 3 2 24 | // s1 25 | // s2 26 | } 27 | } 28 | if (s2 == s1) s1 = s1.next; 29 | // index 0 1 2 3 30 | // dummy 2 3 4 5 6 31 | // s1 32 | // s2 33 | } 34 | 35 | return dummy.next; 36 | } 37 | 38 | public static void main(String[] args) { 39 | InsertionSortLinkedList sol = new InsertionSortLinkedList(); 40 | System.out.println(sol.insertionSort(ListNode.fromArray(new int[]{5,4,1,2,6,3}))); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Solutions/DP/494. Target Sum.md: -------------------------------------------------------------------------------- 1 | # [494. Target Sum](https://leetcode.com/problems/target-sum/) 2 | 3 | ## 2D dp, 6ms, 91.41% 4 | ```java 5 | class Solution { 6 | public int findTargetSumWays(int[] a, int t) { 7 | int n = a.length, sum = Arrays.stream(a).sum(); 8 | if (t < 0) t = -t; 9 | if (sum < t) return 0; 10 | sum += t; 11 | if (sum % 2 != 0) return 0; 12 | t = sum / 2; 13 | 14 | int[][] dp = new int[n+1][t+1]; 15 | 16 | dp[0][0] = 1; 17 | 18 | for (int i = 1; i <= n; i++) { // try each element 19 | for (int j = 0; j <= t; j++) { 20 | dp[i][j] = dp[i-1][j]; // do not use current number 21 | if (j - a[i-1] >= 0) dp[i][j] += dp[i-1][j-a[i-1]]; // use current number 22 | } 23 | } 24 | 25 | return dp[n][t]; 26 | } 27 | } 28 | ``` 29 | ## 1D, dp, 6ms, 91.41% 30 | ```java 31 | class Solution { 32 | public int findTargetSumWays(int[] a, int t) { 33 | int n = a.length, sum = Arrays.stream(a).sum(); 34 | if (t < 0) t = -t; 35 | if (sum < t) return 0; 36 | sum += t; 37 | if (sum % 2 != 0) return 0; 38 | t = sum / 2; 39 | 40 | int[] dp = new int[t+1]; 41 | 42 | dp[0] = 1; 43 | 44 | for (int i = 1; i <= n; i++) { // try each element 45 | for (int j = t; j >= 0; j--) { 46 | if (j - a[i-1] >= 0) dp[j] += dp[j-a[i-1]]; // use current number 47 | } 48 | } 49 | 50 | return dp[t]; 51 | } 52 | } 53 | ``` -------------------------------------------------------------------------------- /CuttingWood.java: -------------------------------------------------------------------------------- 1 | /* 2 | There is a wooden stick with length L >= 1, we need to cut it into pieces, 3 | where the cutting positions are defined in an int array A. 4 | The positions are guaranteed to be in ascending order in the range of [1, L - 1]. 5 | The cost of each cut is the length of the stick segment being cut. 6 | Determine the minimum total cost to cut the stick into the defined pieces. 7 | 8 | Examples 9 | L = 10, A = {2, 4, 7}, the minimum total cost is 10 + 4 + 6 = 20 (cut at 4 first then cut at 2 and cut at 7) 10 | */ 11 | 12 | public class CuttingWood { 13 | 14 | public int minCost(int[] cuts, int length) { 15 | int n; 16 | if (cuts == null || (n = cuts.length) == 0) return 0; 17 | 18 | int[] a = new int[n += 2]; 19 | a[n - 1] = length; 20 | for (int i = 1; i < n - 1; i++) a[i] = cuts[i - 1]; 21 | int[][] M = new int[n][n]; 22 | 23 | for (int diff = 2; diff < n; diff++) 24 | for (int i = 0; i + diff < n; i++) { 25 | int j = i + diff; 26 | int curCutCost = a[j] - a[i]; 27 | M[i][j] = Integer.MAX_VALUE; 28 | for (int k = i + 1; k < j; k++) 29 | M[i][j] = Math.min(M[i][j], curCutCost + M[i][k] + M[k][j]); 30 | } 31 | 32 | return M[0][n-1]; 33 | } 34 | 35 | public static void main(String[] args) { 36 | CuttingWood cw = new CuttingWood(); 37 | System.out.println(cw.minCost(new int[]{3,16,19,28,37,44,47,48,51,52,62}, 67)); // 229 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LongestPalindromicSubstring.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given a string S, find the longest palindromic substring in S. 3 | Assumptions 4 | There exists one unique longest palindromic substring. 5 | The input S is not null. 6 | Examples 7 | Input: "abbc" 8 | Output: "bb" 9 | 10 | Input: "abcbcbd" 11 | Output: "bcbcb" 12 | */ 13 | public class LongestPalindromicSubstring { 14 | public String longestPalindrome(String s) { 15 | int l = 0, r = 0, n = s.length(); 16 | if (n == 0) return ""; 17 | 18 | boolean[][] dp = new boolean[n][n]; // [i, j] in string is palindrome 19 | 20 | for (int j = 0; j < n; j++) 21 | for (int i = 0; i <= j; i++) // fix position of j first, then check all substring [i, j] 22 | if (s.charAt(i) == s.charAt(j) && (i + 1 >= j || dp[i+1][j-1])) { 23 | dp[i][j] = true; 24 | if (j - i > r - l) { // longer Palindromic Substring found 25 | r = j; 26 | l = i; 27 | } 28 | } 29 | 30 | return s.substring(l, r + 1); 31 | } 32 | 33 | public static void main(String[] args) { 34 | LongestPalindromicSubstring lps = new LongestPalindromicSubstring(); 35 | System.out.println(lps.longestPalindrome("abcbcbd").equals("bcbcb")); 36 | System.out.println(lps.longestPalindrome("bcbccaacdca").equals("acdca")); 37 | System.out.println(lps.longestPalindrome("dbdcbdbabbacd").equals("abba")); 38 | System.out.println(lps.longestPalindrome("").equals("")); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /EvaluateReversePolishNotation.java: -------------------------------------------------------------------------------- 1 | import java.util.ArrayDeque; 2 | import java.util.Deque; 3 | 4 | /* 5 | Evaluate the value of an arithmetic expression in Reverse Polish Notation. 6 | Assumption 7 | Valid operators are +, -, *, /. 8 | Each operand may be an integer or another expression. 9 | Examples 10 | ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9 11 | ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6 12 | */ 13 | public class EvaluateReversePolishNotation { 14 | public int evalRPN(String[] tokens) { // TC: O(n) n is the length of tokens, SC:O(n) 15 | Deque stack = new ArrayDeque<>(); 16 | for (String s : tokens) { 17 | Integer x = getInt(s); 18 | if (x != null) stack.offerFirst(x); 19 | else { 20 | int x1 = stack.pollFirst(); 21 | int x2 = stack.pollFirst(); 22 | int res = switch (s) { 23 | case "+" -> x2 + x1; 24 | case "-" -> x2 - x1; 25 | case "*" -> x2 * x1; 26 | default -> x2 / x1; // "/", assume input is always valid 27 | }; 28 | stack.offerFirst(res); 29 | } 30 | } 31 | return stack.peekFirst(); 32 | } 33 | 34 | private Integer getInt(String s) { 35 | Integer res = null; 36 | try { 37 | res = Integer.parseInt(s); 38 | } catch (NumberFormatException ignored) {} 39 | return res; 40 | } 41 | 42 | public static void main(String[] args) { 43 | EvaluateReversePolishNotation erpn = new EvaluateReversePolishNotation(); 44 | System.out.println(erpn.evalRPN(new String[]{"0", "12", "4", "+", "-"}) == -16); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /LongestCommonSubsequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | Find the length of longest common subsequence of two given strings. 3 | 4 | Assumptions 5 | The two given strings are not null 6 | Examples 7 | S = “abcde”, T = “cbabdfe”, the longest common subsequence of s and t is {‘a’, ‘b’, ‘d’, ‘e’}, the length is 4. 8 | 9 | */ 10 | 11 | 12 | public class LongestCommonSubsequence { 13 | public int longest(String s, String t) { 14 | int n = s.length(), m = t.length(); 15 | int[][] M = new int[n + 1][m + 1]; 16 | for (int i = 0; i < n; i++) 17 | for (int j = 0; j < m; j++) 18 | if (s.charAt(i) == t.charAt(j)) M[i+1][j+1] = M[i][j] + 1; 19 | else M[i+1][j+1] = Math.max(M[i][j+1], M[i+1][j]); 20 | 21 | System.out.println(getLongestCommonSubSeq(s, M)); 22 | return M[n][m]; 23 | } 24 | 25 | public String getLongestCommonSubSeq(String s, int[][] M) { 26 | StringBuilder sb = new StringBuilder(); 27 | int rows = M.length, cols = M[0].length; 28 | for (int i = 0; i < rows - 1; i++) 29 | for (int j = 0; j < cols - 1; j++) 30 | if (M[i][j] + 1 == M[i+1][j+1] && rows - i == cols - j) 31 | sb.append(s.charAt(i)); 32 | 33 | return sb.toString(); 34 | } 35 | 36 | public static void main(String[] args) { 37 | LongestCommonSubsequence lcs = new LongestCommonSubsequence(); 38 | lcs.longest("apple", "apppppppppple"); 39 | //System.out.println(); 40 | lcs.longest("tsla", "apple"); 41 | //System.out.println(); 42 | lcs.longest("tatat", "tctct"); 43 | //System.out.println(); 44 | lcs.longest("coconut", "cobanua"); 45 | //System.out.println(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Solutions/DP/1326. Minimum Number of Taps to Open to Water a Garden.md: -------------------------------------------------------------------------------- 1 | # [1326. Minimum Number of Taps to Open to Water a Garden](https://leetcode.com/problems/minimum-number-of-taps-to-open-to-water-a-garden/submissions/) 2 | 3 | ## BFS? Greedy? (1ms) 4 | TC: O(n), SC: O(n) 5 | ```java 6 | class Solution { 7 | public int minTaps(int n, int[] ranges) { 8 | int[] a = new int[++n]; 9 | // convert to jump game II problem 10 | for (int i = 0; i < n; i++) { 11 | int l = i - ranges[i], r = i + ranges[i]; 12 | if (l < 0) l = 0; 13 | if (r > a[l]) a[l] = r; 14 | } 15 | 16 | // use BFS to solve jump game II 17 | int jumps = 0, nextMax = 0, curMax = 0; 18 | // curMax >= i means still can jump, nextMax < n - 1 means still need jump 19 | for (int i = 0; curMax >= i && nextMax < n - 1; curMax = nextMax, jumps++) 20 | while (i <= curMax) 21 | nextMax = Math.max(nextMax, a[i++]); 22 | 23 | return curMax < n - 1 ? -1 : jumps; 24 | } 25 | } 26 | ``` 27 | 28 | ## sort first (15 ms) 29 | TC: O(nlogn), SC: O(1) 30 | ```java 31 | class Solution { 32 | public int minTaps(int n, int[] ranges) { 33 | // create range matrix 34 | int[][] mx = new int[++n][2]; 35 | for (int i = 0; i < n; i++) mx[i] = new int[] {i - ranges[i], i + ranges[i]}; 36 | Arrays.sort(mx, (a, b) -> a[0] - b[0]); 37 | 38 | // greedy? bfs? 39 | int curMax = 0, res = 0; 40 | for (int i = 0, nextMax = 0; i < n && curMax >= mx[i][0] && nextMax < n - 1; res++, curMax = nextMax) 41 | while (i < n && mx[i][0] <= curMax) 42 | nextMax = Math.max(nextMax, mx[i++][1]); 43 | 44 | return curMax < n - 1 ? -1 : res; 45 | } 46 | } 47 | ``` -------------------------------------------------------------------------------- /Solutions/DP/935. Knight Dialer.md: -------------------------------------------------------------------------------- 1 | # [935. Knight Dialer](https://leetcode.com/problems/knight-dialer/) 2 | 3 | [LaiCode 684. Dial with a Knight](https://app.laicode.io/app/problem/684) 4 | 5 | ## Regular DP 6 | TC/SC: O(10*n) 7 | ```java 8 | class Solution { 9 | private static final int[][] map = new int[][]{ 10 | {4, 6}, {6, 8}, {7, 9}, {4, 8}, {3, 9, 0}, {}, {1, 7, 0}, {2, 6}, {1, 3}, {2, 4} 11 | }; 12 | private static final int mod = 1_000_000_007; 13 | public int knightDialer(int n) { 14 | int[][] dp = new int[n + 1][10]; 15 | Arrays.fill(dp[1], 1); 16 | 17 | for (int j = 2; j <= n; j++) 18 | for (int i = 0; i < 10; i++) for (int x : map[i]) 19 | dp[j][i] = (dp[j][i] + dp[j - 1][x]) % mod; 20 | 21 | int res = 0; 22 | for (int x : dp[n]) res = (res + x) % mod; 23 | 24 | return res; 25 | } 26 | } 27 | ``` 28 | 29 | ## Space Optimized (32ms, 96.14%; 38.7MB, 100%) 30 | TC: O(10 * n), SC: O(20) 31 | ```java 32 | class Solution { 33 | private static final int[][] map = new int[][]{ 34 | {4, 6}, {6, 8}, {7, 9}, {4, 8}, {3, 9, 0}, {}, {1, 7, 0}, {2, 6}, {1, 3}, {2, 4} 35 | }; 36 | private static final int mod = 1_000_000_007; 37 | public int knightDialer(int n) { 38 | int[][] dp = new int[2][10]; 39 | Arrays.fill(dp[0], 1); 40 | int row = 0; 41 | 42 | for (int j = 1; j < n; j++) { 43 | Arrays.fill(dp[row = 1 ^ row], 0); // or use 1 - row, j % 2, all works 44 | for (int i = 0; i < 10; i++) for (int x : map[i]) 45 | dp[row][i] = (dp[row][i] + dp[1 ^ row][x]) % mod; 46 | } 47 | int res = 0; 48 | for (int x : dp[row]) res = (res + x) % mod; 49 | 50 | return res; 51 | } 52 | } 53 | ``` -------------------------------------------------------------------------------- /Solutions/DP/1937. Maximum Number of Points with Cost.md: -------------------------------------------------------------------------------- 1 | # [1937. Maximum Number of Points with Cost](https://leetcode.com/problems/maximum-number-of-points-with-cost/) 2 | 3 | ## With runmax 4 | ```java 5 | class Solution { 6 | public long maxPoints(int[][] pts) { 7 | int n = pts[0].length; 8 | long[] pre = new long[n], cur = new long[n]; 9 | 10 | for (int j = 0; j < pts[0].length; j++) 11 | cur[j] = pre[j] = pts[0][j]; 12 | 13 | for (int i = 1; i < pts.length; i++) { 14 | long runMax = 0; 15 | for (int j = 0; j < n; j++) 16 | cur[j] = runMax = Math.max(runMax - 1, pre[j]); 17 | 18 | 19 | for (int j = n - 1; j >= 0; j--) 20 | cur[j] = Math.max(runMax = Math.max(runMax - 1, pre[j]), cur[j]) + pts[i][j]; 21 | 22 | 23 | pre = cur; 24 | } 25 | 26 | long res = cur[0]; 27 | for (int j = 1; j < n; j++) 28 | if (cur[j] > res) res = cur[j]; 29 | 30 | return res; 31 | } 32 | } 33 | ``` 34 | 35 | ## Solution 2 36 | ```java 37 | class Solution { 38 | public long maxPoints(int[][] pts) { 39 | int n = pts[0].length; 40 | long[] dp = new long[n]; 41 | 42 | for (int i = 0; i < pts.length; i++) { 43 | int[] row = pts[i]; 44 | for (int j = 0; j < n; j++) dp[j] += row[j]; 45 | if (i == pts.length - 1) break; 46 | for (int j = 1; j < n; j++) dp[j] = Math.max(dp[j], dp[j - 1] - 1); 47 | for (int j = n - 2; j >= 0; j--) dp[j] = Math.max(dp[j], dp[j + 1] - 1); 48 | } 49 | 50 | long res = dp[0]; 51 | for (int j = 1; j < n; j++) if (dp[j] > res) res = dp[j]; 52 | return res; 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /Tree/VerticalListOfBinaryTree.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | 3 | import util.TreeNode; 4 | 5 | import java.util.*; 6 | 7 | public class VerticalListOfBinaryTree { 8 | public static void main(String[] args) { 9 | VerticalListOfBinaryTree sol = new VerticalListOfBinaryTree(); 10 | System.out.println(sol.verticalPrint(TreeNode.fromLevelOrder(new Integer[]{4, 2, null, 1, 3, null, null, 7, 9}))); 11 | } 12 | 13 | static class Pair { 14 | TreeNode node; 15 | int idx; 16 | Pair(TreeNode node, int idx) { 17 | this.node = node; 18 | this.idx = idx; 19 | } 20 | } 21 | public List> verticalPrint(TreeNode root) { 22 | Map> map = new HashMap<>(); 23 | int[] range = bfs(root, map); 24 | 25 | List> res = new ArrayList<>(range[1] - range[0] + 1); 26 | 27 | for (int i = range[0]; i <= range[1]; i++) res.add(map.get(i)); 28 | 29 | return res; 30 | } 31 | 32 | private int[] bfs(TreeNode root, Map> map) { 33 | Queue q = new ArrayDeque<>(); 34 | if (root != null) q.offer(new Pair(root, 0)); 35 | 36 | int min = 0, max = -1; // so that size (max - min + 1) is 0 when root is null 37 | 38 | while (!q.isEmpty()) { 39 | Pair cur = q.poll(); 40 | min = Math.min(min, cur.idx); 41 | max = Math.max(max, cur.idx); 42 | 43 | var list = map.getOrDefault(cur.idx, new ArrayList<>()); 44 | list.add(cur.node.key); 45 | map.put(cur.idx, list); 46 | 47 | if (cur.node.left != null) q.offer(new Pair(cur.node.left , cur.idx - 1)); 48 | if (cur.node.right != null) q.offer(new Pair(cur.node.right, cur.idx + 1)); 49 | } 50 | 51 | return new int[] {min, max}; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Solutions/GraphSearch/317. Shortest Distance from All Buildings.md: -------------------------------------------------------------------------------- 1 | # [317. Shortest Distance from All Buildings](https://leetcode.com/problems/shortest-distance-from-all-buildings/) 2 | 3 | ## Starting from houses (114ms, 98.99%) 4 | TC: O(k * m * n) let k be number of houses(value 1) 5 | 6 | SC: O(m*n) 7 | ## Summary 8 | 9 | ```java 10 | class Solution { 11 | private static final int[][] dirs = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; 12 | public int shortestDistance(int[][] grid) { 13 | int m = grid.length, n = grid[0].length; 14 | 15 | int[][] dis = new int[m][n]; 16 | 17 | int round = 0; 18 | for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) 19 | if (grid[i][j] == 1) 20 | bfs(grid, dis, i, j, m, n, round--); 21 | 22 | int res = Integer.MAX_VALUE; 23 | for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) 24 | if (grid[i][j] == round && dis[i][j] < res) 25 | res = dis[i][j]; 26 | 27 | return res == Integer.MAX_VALUE ? -1 : res; 28 | } 29 | 30 | private void bfs(int[][] grid, int[][] dis, int i, int j, int m, int n, int round) { 31 | Queue q = new ArrayDeque<>(); 32 | q.offer(new int[] {i, j}); 33 | 34 | int step = 0; 35 | while (!q.isEmpty()) { 36 | int size = q.size(); 37 | while (size-- > 0) { 38 | var cur = q.poll(); 39 | for (var dir : dirs) { 40 | int i2 = cur[0] + dir[0], j2 = cur[1] + dir[1]; 41 | if (i2 < 0 || j2 < 0 || i2 >= m || j2 >= n || grid[i2][j2] != round) continue; 42 | dis[i2][j2] += step + 1; 43 | grid[i2][j2]--; 44 | q.offer(new int[] {i2, j2}); 45 | } 46 | } 47 | step++; 48 | } 49 | } 50 | } 51 | ``` -------------------------------------------------------------------------------- /OOD/Student.java: -------------------------------------------------------------------------------- 1 | package OOD; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.*; 6 | 7 | enum Grade0 {Fail, Pass} 8 | enum Grade1 {F, E, D, C, B, A} 9 | 10 | public record Student(int id, String name, int math, Grade0 pe, Grade1 en) implements Comparable { 11 | static int[] ID = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9}; 12 | static String[] NAME = new String[]{"Sunny", "Pete", "Jason", "Lucy", "Kate", "Anna", "Nate", "John", "Sun"}; 13 | static int[] MATH = new int[] {90, 80, 75, 60, 83, 95, 77, 93, 88}; 14 | static Grade0[] PE = new Grade0[] {Grade0.Pass, Grade0.Pass, Grade0.Fail, Grade0.Fail, Grade0.Pass, Grade0.Fail, Grade0.Fail, Grade0.Pass, Grade0.Fail}; 15 | static Grade1[] EN = new Grade1[] {Grade1.A, Grade1.B, Grade1.F, Grade1.D, Grade1.E, Grade1.D, Grade1.A, Grade1.C, Grade1.B}; 16 | 17 | @Override 18 | public int compareTo(@NotNull Student o) { 19 | return Integer.compare(id, o.id); 20 | } 21 | 22 | public static Student[] sampleArray() { 23 | Student[] res = new Student[NAME.length]; 24 | 25 | for (int i = 0; i < NAME.length; i++) 26 | res[i] = new Student(ID[i], NAME[i], MATH[i], PE[i], EN[i]); 27 | 28 | return res; 29 | } 30 | 31 | public static List sampleList() { 32 | List res = new ArrayList<>(NAME.length); 33 | 34 | for (int i = 0; i < NAME.length; i++) 35 | res.add(new Student(ID[i],NAME[i], MATH[i], PE[i], EN[i])); 36 | 37 | Collections.shuffle(res); 38 | return res; 39 | } 40 | 41 | public static void main(String[] args) { 42 | List list = sampleList(); 43 | System.out.println(Arrays.toString(StudentComparators.values())); 44 | list.sort(StudentComparators.valueOf("EN").reversed()); 45 | for (Student stu : list) System.out.println(stu); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Solutions/String and Array/2163. Minimum Difference in Sums After Removal of Elements.md: -------------------------------------------------------------------------------- 1 | # [2163. Minimum Difference in Sums After Removal of Elements](https://leetcode.com/problems/minimum-difference-in-sums-after-removal-of-elements/) 2 | 3 | ## TC O(4n), SC: O(n) (array length is 3n) 4 | ```java 5 | class Solution { 6 | public long minimumDifference(int[] a) { 7 | int n3 = a.length, n = n3 / 3; 8 | Queue q1 = new PriorityQueue<>((x, y) -> Integer.compare(y, x)); // maxHeap, to min first n sum 9 | Queue q2 = new PriorityQueue<>(); // minHeap, to max last n sum 10 | 11 | long[] minSumLeft = new long[n+1]; // rolling min sum for first n subsequence 12 | long sum1 = 0, sum2 = 0; // temp(cur) variable to calc rolling sum for first and last n 13 | for (int i = 0; i < n; i++) { // init of 1st n sum 14 | q1.offer(a[i]); 15 | sum1 += a[i]; 16 | } 17 | minSumLeft[0] = sum1; 18 | for (int i = n; i < n3-n; i++) { // rolling min sum of first n 19 | if (a[i] < q1.peek()) { 20 | sum1 += a[i] - q1.poll(); 21 | q1.offer(a[i]); 22 | } 23 | minSumLeft[i-n+1] = sum1; 24 | } 25 | 26 | for (int i = n3-1; i > n3-1-n; i--) { // init of last n sum 27 | q2.offer(a[i]); 28 | sum2 += a[i]; 29 | } 30 | 31 | long res = minSumLeft[n] - sum2; // first result 32 | 33 | // rolling back from right to left to get what we need 34 | for (int i = n3-n-1; i >= n; i--) { // 2n-1 to n, n-1 to 0, total n round 35 | if (a[i] > q2.peek()) { 36 | sum2 += a[i] - q2.poll(); 37 | q2.offer(a[i]); 38 | } 39 | res = Math.min(res, minSumLeft[i-n] - sum2); 40 | } 41 | 42 | return res; 43 | } 44 | } 45 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/687. Longest Univalue Path.md: -------------------------------------------------------------------------------- 1 | # Longest Uni-value Path 2 | 3 | [LeetCode 687. Longest Univalue Path](https://leetcode.com/problems/longest-univalue-path/) 4 | 5 | TC: O(n), SC: O(height) 6 | ```java 7 | class Solution { 8 | int max; 9 | public int longestUnivaluePath(TreeNode root) { 10 | max = 0; 11 | if (root == null) return max; 12 | dfs(root); 13 | return max - 1; 14 | } 15 | 16 | private int dfs(TreeNode root) { 17 | int cur = 1, left = 0, right = 0; 18 | 19 | if (root.left != null) { 20 | left = dfs(root.left ); 21 | if (root.val != root.left.val) left = 0; 22 | cur += left; 23 | } 24 | 25 | if (root.right != null) { 26 | right = dfs(root.right); 27 | if (root.val != root.right.val) right = 0; 28 | cur += right; 29 | } 30 | 31 | if (cur > max) max = cur; 32 | 33 | return 1 + Math.max(left, right); 34 | } 35 | } 36 | ``` 37 | [LaiCode 669. Longest Uni-value path](https://app.laicode.io/app/problem/669) 38 | 39 | TC: O(n), SC: O(height) 40 | ```java 41 | class Solution { 42 | int max; 43 | public int longestUnivaluePath(TreeNode root) { 44 | max = 0; 45 | if (root != null) dfs(root); 46 | return max; 47 | } 48 | 49 | private int dfs(TreeNode root) { 50 | int cur = 1, left = 0, right = 0; 51 | 52 | if (root.left != null) { 53 | left = dfs(root.left ); 54 | if (root.key != root.left.key) left = 0; 55 | cur += left; 56 | } 57 | 58 | if (root.right != null) { 59 | right = dfs(root.right); 60 | if (root.key != root.right.key) right = 0; 61 | cur += right; 62 | } 63 | 64 | if (cur > max) max = cur; 65 | 66 | return 1 + Math.max(left, right); 67 | } 68 | } 69 | ``` -------------------------------------------------------------------------------- /MergeKSortedArray.java: -------------------------------------------------------------------------------- 1 | /* 2 | Merge K sorted array into one big sorted array in ascending order. 3 | 4 | Assumptions 5 | The input arrayOfArrays is not null, none of the arrays is null either. 6 | */ 7 | 8 | 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Arrays; 12 | import java.util.PriorityQueue; 13 | 14 | public class MergeKSortedArray { 15 | 16 | static class Entry implements Comparable { 17 | int i, j, v; 18 | Entry(int i, int j, int v) { 19 | this.i = i; 20 | this.j = j; 21 | this.v = v; 22 | } 23 | 24 | @Override 25 | public int compareTo(Entry e) { 26 | return Integer.compare(this.v, e.v); 27 | } 28 | } 29 | 30 | public int[] merge(int[][] aa) { 31 | // Write your solution here 32 | PriorityQueue pq = new PriorityQueue<>(11); 33 | int length = 0; 34 | for (int i = 0; i < aa.length; i++) { 35 | int[] a = aa[i]; 36 | length += a.length; 37 | if (a.length != 0) pq.offer(new Entry(i, 0, a[0])); 38 | } 39 | int[] res = new int[length]; 40 | 41 | for (int i = 0;!pq.isEmpty();) { 42 | Entry cur = pq.poll(); 43 | res[i++] = cur.v; 44 | if (++cur.j < aa[cur.i].length) { 45 | cur.v = aa[cur.i][cur.j]; 46 | pq.offer(cur); 47 | } 48 | } 49 | return res; 50 | } 51 | 52 | public static void main(String[] args) { 53 | MergeKSortedArray msa = new MergeKSortedArray(); 54 | System.out.println(Arrays.toString(msa.merge(new int[][]{{3}, {1, 2, 3, 4, 5}}))); // [1, 2, 3, 3, 4, 5] 55 | System.out.println(Arrays.toString(msa.merge(new int[][]{{11, 12, 13, 14, 15}, {3}, {1, 2}, {4, 5, 6, 7}, {8, 9, 10}}))); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Solutions/String and Array/150. Evaluate Reverse Polish Notation.md: -------------------------------------------------------------------------------- 1 | # [150. Evaluate Reverse Polish Notation](https://leetcode.com/problems/evaluate-reverse-polish-notation/) 2 | [LaiCode 8. Evaluate Reverse Polish Notation](https://app.laicode.io/app/problem/8) 3 | TC: O(n), SC: O(n) 4 | 5 | ## 6 | 7 | ```java 8 | class Solution { 9 | public int evalRPN(String[] a) { 10 | Deque stack = new ArrayDeque<>(); 11 | 12 | for (String s : a) { 13 | switch (s) { 14 | case "+" -> stack.offerFirst( stack.pollFirst() + stack.pollFirst()); 15 | case "-" -> stack.offerFirst(-stack.pollFirst() + stack.pollFirst()); 16 | case "*" -> stack.offerFirst( stack.pollFirst() * stack.pollFirst()); 17 | case "/" -> { 18 | int val = stack.pollFirst(); 19 | stack.offerFirst(stack.pollFirst() / val); 20 | } 21 | default -> stack.offerFirst(Integer.parseInt(s)); 22 | } 23 | } 24 | 25 | return stack.peekFirst(); 26 | } 27 | } 28 | ``` 29 | 30 | ```java 31 | class Solution { 32 | public int evalRPN(String[] tokens) { 33 | Deque stack = new ArrayDeque<>(); // for numbers 34 | 35 | for (String s : tokens) { 36 | if (s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) { 37 | int x2 = stack.pollFirst(); 38 | int x1 = stack.pollFirst(); 39 | 40 | switch (s) { 41 | case "+" -> stack.offerFirst(x1 + x2); 42 | case "-" -> stack.offerFirst(x1 - x2); 43 | case "*" -> stack.offerFirst(x1 * x2); 44 | case "/" -> stack.offerFirst(x1 / x2); 45 | } 46 | 47 | } else stack.offerFirst(Integer.parseInt(s)); 48 | } 49 | 50 | return stack.peekFirst(); 51 | } 52 | } 53 | ``` -------------------------------------------------------------------------------- /Solutions/Misc/2080. Range Frequency Queries.md: -------------------------------------------------------------------------------- 1 | # [2080. Range Frequency Queries](https://leetcode.com/problems/range-frequency-queries/) 2 | 3 | ## Segment Tree 4 | Build Tree: TC: O(4n), SC: O(4n)? 5 | 6 | Query: TC: O(logn) 7 | ```java 8 | class Node { 9 | int start, end; 10 | Node left, right; 11 | Map map = new HashMap<>(); 12 | public Node(int s, int e, Node l, Node r) { 13 | start = s; 14 | end = e; 15 | left = l; 16 | right = r; 17 | } 18 | public Node(int s, int e) { 19 | this(s, e, null, null); 20 | } 21 | } 22 | class RangeFreqQuery { 23 | Node root; 24 | int[] a; 25 | public RangeFreqQuery(int[] arr) { 26 | a = arr; 27 | root = build(0, a.length-1); 28 | } 29 | 30 | private Node build(int start, int end) { 31 | if (start == end) { 32 | Node node = new Node(start, end); 33 | node.map.put(a[end], 1); 34 | return node; 35 | } 36 | 37 | int mid = start + (end - start) / 2; 38 | Node left = build(start, mid); 39 | Node right = build(mid+1, end); 40 | Node node = new Node(start, end, left, right); 41 | 42 | node.map = new HashMap<>(left.map); 43 | for (Map.Entry e : right.map.entrySet()) 44 | node.map.put(e.getKey(), node.map.getOrDefault(e.getKey(), 0) + e.getValue()); 45 | 46 | return node; 47 | } 48 | 49 | public int query(int left, int right, int value) { 50 | return query(root, left, right, value); 51 | } 52 | 53 | private int query(Node node, int start, int end, int x) { 54 | if (!node.map.containsKey(x) || node.start > end || node.end < start) return 0; 55 | if (start <= node.start && end >= node.end) return node.map.get(x); 56 | return query(node.left, start, end, x) + query(node.right, start, end, x); 57 | } 58 | } 59 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/1325. Delete Leaves With a Given Value.md: -------------------------------------------------------------------------------- 1 | # [1325. Delete Leaves With a Given Value](https://leetcode.com/problems/delete-leaves-with-a-given-value/) 2 | Same as: [Delete Zero Nodes From Leaf](https://app.laicode.io/app/problem/322) 3 | ### TC & SC 4 | TC: O(n) 5 | 6 | SC: O(height) 7 | 8 | ### LaiCode 9 | ```java 10 | class Solution { 11 | public TreeNode deleteZero(TreeNode root) { 12 | if (root == null) return null; 13 | root.left = deleteZero(root.left ); 14 | root.right = deleteZero(root.right); 15 | if (root.key == 0 && root.left == null && root.right == null) return null; 16 | return root; 17 | } 18 | } 19 | ``` 20 | ### LeetCode 21 | ```java 22 | class Solution { 23 | public TreeNode removeLeafNodes(TreeNode root, int target) { 24 | if (root == null) return null; 25 | root.left = removeLeafNodes(root.left , target); 26 | root.right = removeLeafNodes(root.right, target); 27 | if (root.val == target && root.left == null && root.right == null) return null; 28 | return root; 29 | } 30 | } 31 | ``` 32 | # [LaiCode 407. Trim Binary Tree by Path Cost](https://app.laicode.io/app/problem/407) 33 | 34 | ### TC & SC 35 | as we only go down depth of k: 36 | 37 | TC: Omin(n, (2^k)) 38 | 39 | SC: O(min(height, k)) 40 | 41 | ```java 42 | class Solution { 43 | public TreeNode trimTree(TreeNode root, int k) { 44 | return dfs(root, k - 1, 0); // if at level k - 1 or smaller, a node is leaf node, then it should be deleted 45 | } 46 | 47 | private TreeNode dfs(TreeNode root, int k, int depth) { 48 | if (root == null || depth >= k) return root; // if k == 0 we dont delete anything, as we only delete level < k 49 | root.left = dfs(root.left, k, depth + 1); 50 | root.right = dfs(root.right, k, depth + 1); 51 | // once we get here, depth is < k for sure, as depth >= k has been returned by corner case 52 | if (root.left == null && root.right == null) return null; 53 | return root; 54 | } 55 | } 56 | ``` -------------------------------------------------------------------------------- /Solutions/String and Array/1209. Remove All Adjacent Duplicates in String II.md: -------------------------------------------------------------------------------- 1 | # [1209. Remove All Adjacent Duplicates in String II](https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string-ii/) 2 | 3 | ## concise (4ms, 99.96%) 4 | TC: O(n), SC: O(n) 5 | ```java 6 | class Solution { 7 | public String removeDuplicates(String s, int k) { 8 | int top = -1, n = s.length(); 9 | char[] arr = s.toCharArray(); 10 | int[] cnt = new int[n]; 11 | 12 | for (int i = 0; i < n; i++) { 13 | arr[++top] = arr[i]; 14 | cnt[top] = top > 0 && arr[top] == arr[top - 1] ? cnt[top - 1] + 1 : 1; 15 | if (cnt[top] == k) top -= k; 16 | } 17 | 18 | return new String(arr, 0, top + 1); 19 | } 20 | } 21 | ``` 22 | 23 | ## a bit hard to understand (3ms, 100%) 24 | TC: O(n), SC: O(n) 25 | ```java 26 | class Solution { 27 | public String removeDuplicates(String str, int k) { 28 | char[] a = str.toCharArray(); 29 | int[] s = new int[a.length]; 30 | 31 | int t1 = -1, t2 = -1; 32 | for (int i = 0; i < a.length; ) { 33 | int start = i; 34 | while (i < a.length && a[i] == a[start]) i++; 35 | int len1 = t1 == -1 || a[t1] != a[start] ? 0 : t1 - s[t2]; // (s[t2], t1] 36 | int len = len1 + i - start; 37 | int keep = len % k; 38 | if (keep > 0) { 39 | if (keep <= len1) t1 -= len1 - keep; 40 | else { 41 | if (len1 == 0) s[++t2] = t1; // exclusive 42 | for (start = i - keep + len1; start < i; ) a[++t1] = a[start++]; 43 | } 44 | } else if (len1 > 0) t1 = s[t2--]; 45 | } 46 | 47 | return new String(a, 0, t1 + 1); 48 | } 49 | } 50 | // System.out.printf("%s vs %s\n%si\n%s\n%ss\n", new String(a), new String(a, 0, t1 + 1), " ".repeat(i), t1 >= 0 ? " ".repeat(t1) + "t" : "", " ".repeat(start)); 51 | ``` -------------------------------------------------------------------------------- /LargestSubMatrixSum.java: -------------------------------------------------------------------------------- 1 | /* Given a matrix that contains integers, find the sub matrix with the largest sum. Return the sum of the sub matrix. 2 | 3 | Assumptions 4 | The given matrix is not null and has size of M * N, where M >= 1 and N >= 1 5 | Examples 6 | { {1, -2, -1, 4}, 7 | {1, -1, 1, 1}, 8 | {0, -1, -1, 1}, 9 | {0, 0, 1, 1} } 10 | 11 | the largest sub matrix sum is (-1) + 4 + 1 + 1 + (-1) + 1 + 1 + 1 = 7. 12 | */ 13 | 14 | 15 | import java.util.Arrays; 16 | 17 | class LargestSubMatrixSum { 18 | public int largest(int[][] mx) { // TC: O(n^2*2n) → O(n^3), SC: O(n) 19 | int n = mx.length, m = mx[0].length; 20 | 21 | int res = Integer.MIN_VALUE; 22 | for (int i = 0; i < n; i++) { // from row i 23 | int[] prefixSum = new int[m]; // a row which stores prefix sum for each column 24 | for (int j = i; j < n; j++) // to row j 25 | res = Math.max(res, max(prefixSum(prefixSum, mx[j]))); 26 | } 27 | 28 | return res; 29 | } 30 | 31 | private int[] prefixSum(int[] prefixSum, int[] curRow) { // O(n) 32 | for (int i = 0; i < curRow.length; i++) prefixSum[i] += curRow[i]; 33 | return prefixSum; 34 | } 35 | 36 | private int max(int[] A) { // O(n) 37 | int max = A[0], cur = A[0]; 38 | for (int i = 1; i < A.length; i++) { 39 | cur = Math.max(cur, 0) + A[i]; 40 | if (cur > max) max = cur; 41 | } 42 | return max; 43 | } 44 | 45 | public static void main(String[] args) { 46 | 47 | LargestSubMatrixSum lss = new LargestSubMatrixSum(); 48 | int[][] mx = new int[][]{ 49 | {1, -2, -1, 4}, 50 | {1, -1, 1, 1}, 51 | {0, -1, -1, 1}, 52 | {0, 0, 1, 1} }; 53 | System.out.println(lss.largest(new int[][]{{1}})); // 1 54 | System.out.println(lss.largest(mx)); // 7 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /SortWithTwoStacks.java: -------------------------------------------------------------------------------- 1 | import java.util.LinkedList; 2 | 3 | public class SortWithTwoStacks { 4 | // using inserting sort (插入排序) 5 | // s2 will always have values sorted descending from top (ascending from bottom) 6 | // first step s2 is empty, and we move 1 element to s2, which is for sure sorted 7 | // starting second step, we poll an int from s1 first (poll value from s1 is always the first step of each iteration) 8 | // then we poll all values in s2 that's larger than the value we just polled, and push them into s1 9 | // then we offer(insert) the cur value polled at the start of s1 into s2, now this value is at the right position (exactly like insertion sort) 10 | // 11 | // Now we resume polling element from s1 to s2, all elements we just polled from s2 to s1 will be larger than current top of s2 for sure 12 | // so these will be put back to s2 in the right sequence, everything in s2 is sorted at all time 13 | // 14 | // After s1 is done, s2 will have all elements sorted ascending from bottom, then we move everything from s2 to s1, 15 | // s1 will have everything ascending from top 16 | public void sort(LinkedList s1) { 17 | if (s1 == null || s1.size() <= 1) return; 18 | LinkedList s2 = new LinkedList<>(); 19 | 20 | while (!s1.isEmpty()) { 21 | int cur = s1.pollFirst(); 22 | 23 | while (!s2.isEmpty() && s2.peekFirst() > cur) 24 | s1.offerFirst(s2.pollFirst()); 25 | 26 | s2.offerFirst(cur); 27 | } 28 | 29 | while (!s2.isEmpty()) s1.offerFirst(s2.pollFirst()); 30 | 31 | } 32 | 33 | public static void main(String[] args) { 34 | SortWithTwoStacks sol = new SortWithTwoStacks(); 35 | LinkedList s1 = new LinkedList<>(); 36 | sol.sort(s1); 37 | for (int i = 0; i < 10; i++) s1.offerFirst((int) (Math.random() * 10)); 38 | System.out.println(s1); 39 | sol.sort(s1); 40 | System.out.println(s1); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Solutions/Stack and Queue/353. Design Snake Game.md: -------------------------------------------------------------------------------- 1 | # [353. Design Snake Game](https://leetcode.com/problems/design-snake-game/) 2 | 3 | ## solution/思路 4 | 1. 起始长度1:, 起始点: <0, 0> 5 | 2. 每吃到一个食物长度增加1 6 | 3. 走出边界会死,撞到自己会死, return -1 7 | 4. 每走一次: 8 | 1. 没有吃到食物: 尾巴短1,头增加1 9 | 2. 吃到食物: 头往指定方向增加1 10 | 3. 先砍尾巴,再加头,不然可能会死 11 | 5. design 12 | 1. 需要一个set来看🐍的身体占用了哪些点,用来检测下一步会不会撞到自己 13 | 2. 需要一个deque/queue来记录🐍身体每个点的顺序,因为要砍尾巴 14 | 3. 因为LeetCode的限制,不真的建立matrix,全部用坐标来模拟 15 | 4. score 就是set或者deque/queue的size - 1 16 | 17 | ```java 18 | class SnakeGame { 19 | record Cell(int i, int j) { 20 | } 21 | 22 | int w, h; 23 | int[][] food; 24 | int i, j; // head coordination 25 | int idx; // food index, which food to show right now, default 0 26 | Set set = new HashSet<>(); 27 | Queue q = new ArrayDeque<>(); 28 | 29 | public SnakeGame(int w, int h, int[][] food) { 30 | this.w = w; 31 | this.h = h; 32 | this.food = food; 33 | Cell start = new Cell(0, 0); 34 | set.add(start); 35 | q.offer(start); 36 | } 37 | 38 | public int move(String dir) { 39 | switch (dir) { 40 | case "U" -> i--; 41 | case "D" -> i++; 42 | case "L" -> j--; 43 | case "R" -> j++; 44 | } 45 | 46 | if (i < 0 || j < 0 || i >= h || j >= w) return -1; 47 | 48 | if (isFood()) idx++; // ate current food, move 49 | else set.remove(q.poll()); // no food, remove tail 50 | 51 | Cell newHead = new Cell(i, j); 52 | if (!set.add(newHead)) return -1; 53 | q.offer(newHead); 54 | 55 | return q.size() - 1; 56 | } 57 | 58 | public boolean isFood() { 59 | if (idx >= food.length) return false; 60 | var f = food[idx]; 61 | return f[0] == i && f[1] == j; 62 | } 63 | } 64 | 65 | /** 66 | * Your SnakeGame object will be instantiated and called as such: 67 | * SnakeGame obj = new SnakeGame(width, height, food); 68 | * int param_1 = obj.move(direction); 69 | */ 70 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/2096. Step-By-Step Directions From a Binary Tree Node to Another.md: -------------------------------------------------------------------------------- 1 | # [2096. Step-By-Step Directions From a Binary Tree Node to Another](https://leetcode.com/problems/step-by-step-directions-from-a-binary-tree-node-to-another/submissions/) 2 | ## 24ms, 98.13%, 70.7mb, 98.74% 3 | ```java 4 | /** 5 | * Definition for a binary tree node. 6 | * public class TreeNode { 7 | * int val; 8 | * TreeNode left; 9 | * TreeNode right; 10 | * TreeNode() {} 11 | * TreeNode(int val) { this.val = val; } 12 | * TreeNode(int val, TreeNode left, TreeNode right) { 13 | * this.val = val; 14 | * this.left = left; 15 | * this.right = right; 16 | * } 17 | * } 18 | */ 19 | class Solution { 20 | private boolean find(TreeNode n, int val, StringBuilder sb) { 21 | if (n.val == val) return true; 22 | if (n.left != null && find(n.left , val, sb)) sb.append("L"); 23 | else if (n.right != null && find(n.right, val, sb)) sb.append("R"); 24 | return sb.length() > 0; 25 | } 26 | 27 | private boolean depth(TreeNode n, int val, int[] d) { 28 | if (n.val == val) return true; 29 | if (n.left != null && depth(n.left , val, d)) d[0]++; 30 | else if (n.right != null && depth(n.right, val, d)) d[0]++; 31 | return d[0] > 0; 32 | } 33 | 34 | public String getDirections(TreeNode root, int x, int y) { 35 | TreeNode lca = lca(root, x, y); 36 | StringBuilder sb = new StringBuilder(); 37 | int[] d = new int[1]; 38 | depth(lca, x, d); // find depth from lca to start 39 | find (lca, y, sb); // find path from destination back to lca 40 | return "U".repeat(d[0]) + sb.reverse(); 41 | } 42 | 43 | private TreeNode lca(TreeNode root, int x, int y) { 44 | if (root == null || root.val == x || root.val == y) return root; 45 | TreeNode l = lca (root.left , x, y); 46 | TreeNode r = lca (root.right, x, y); 47 | return l != null ? r != null ? root : l : r; 48 | } 49 | } 50 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/2196. Create Binary Tree From Descriptions.md: -------------------------------------------------------------------------------- 1 | # [2196. Create Binary Tree From Descriptions](https://leetcode.com/problems/create-binary-tree-from-descriptions/) 2 | 3 | ## map, 60ms, faster than 97.26%, 51MB, less than 97.87% 4 | ```java 5 | class Solution { 6 | public TreeNode createBinaryTree(int[][] descriptions) { 7 | Map map = new HashMap<>(); 8 | Set set = new HashSet<>(); 9 | 10 | for (var d : descriptions) { 11 | int parent = d[0], child = d[1], isLeft = d[2]; 12 | TreeNode par = map.get(parent); 13 | if (par == null) map.put(parent, par = new TreeNode(parent)); 14 | 15 | set.add(child); 16 | TreeNode node = map.get(child); 17 | if (node == null) map.put(child, node = new TreeNode(child)); 18 | if (isLeft == 1) par.left = node; 19 | else par.right = node; 20 | } 21 | 22 | for (var a : descriptions) if (!set.contains(a[0])) return map.get(a[0]); 23 | 24 | return null; 25 | } 26 | } 27 | ``` 28 | ## use array as map, 10ms, 100.00%, 51.7MB, 93.62% 29 | ```java 30 | class Solution { 31 | public TreeNode createBinaryTree(int[][] descriptions) { 32 | int max = 0; 33 | for (var a : descriptions) if (a[0] > max) max = a[0]; 34 | for (var a : descriptions) if (a[1] > max) max = a[1]; 35 | 36 | TreeNode[] m = new TreeNode[max+1]; 37 | boolean [] p = new boolean [max+1]; // has parent 38 | 39 | for (var d : descriptions) { 40 | int par = d[0], child = d[1], isLeft = d[2]; 41 | if (m[par] == null) m[par] = new TreeNode(par); 42 | 43 | p[child] = true; 44 | if (m[child] == null) m[child] = new TreeNode(child); 45 | if (isLeft == 1) m[par].left = m[child]; 46 | else m[par].right = m[child]; 47 | } 48 | 49 | for (var a : descriptions) if (!p[a[0]]) return m[a[0]]; 50 | 51 | return null; 52 | } 53 | } 54 | ``` -------------------------------------------------------------------------------- /Solutions/DP/2355. Maximum Number of Books You Can Take.md: -------------------------------------------------------------------------------- 1 | # [2355. Maximum Number of Books You Can Take](https://leetcode.com/problems/maximum-number-of-books-you-can-take/) 2 | 3 | ## O(n^2) brute force (will TLE at case 71 of 84) 4 | ```java 5 | class Solution { 6 | public long maximumBooks(int[] a) { 7 | int n = a.length; 8 | long res = 0; 9 | for (int i = 0; i < n; i++) { 10 | if (i == n - 1 || a[i+1] <= a[i]) { 11 | long cur = a[i], num = a[i]; 12 | for (int j = i - 1; j >= 0; j--) { 13 | num = Math.min(a[j], Math.max(0, num - 1)); 14 | if (num == 0) break; 15 | cur += num; 16 | } 17 | res = Math.max(res, cur); 18 | } 19 | } 20 | return res; 21 | } 22 | } 23 | ``` 24 | ## Mono-stack + dp, TC/SC: O(n), 19ms, 100% 25 | Not so easy to explain, I'll come back later. 26 | 27 | Use array to fake stack significantly increases the speed, but use more spaces... 28 | ```java 29 | class Solution { 30 | public long maximumBooks(int[] a) { 31 | int n = a.length, top = -1; // top == -1 means stack is empty 32 | int[] s = new int[n]; // our stack 33 | long[] dp = new long[n]; // for corner case 34 | 35 | for (int i = 0; i < n; s[++top] = i++) { 36 | while (top >= 0 && a[i] - a[s[top]] < i - s[top]) top--; 37 | int j = top >= 0 ? s[top] + 1 : Math.max(0, i - a[i] + 1); // if stack is not empty, it's a trapezoid or single number, otherwise its a triangle 38 | int len = i - j + 1; 39 | int left = a[i] - (i - j), right = a[i]; 40 | long area = (long) (right + left) * len / 2; // area of the trapezoid or triangle (or single number) cur number can get 41 | dp[i] = top >= 0 ? area + dp[j-1] : area; // top >= - means stack is not empty, thats means dp[j-1] can be added 42 | } 43 | 44 | long res = dp[0]; 45 | for (long x : dp) if (x > res) res = x; 46 | return res; 47 | } 48 | } 49 | ``` -------------------------------------------------------------------------------- /Solutions/GraphSearch/399. Evaluate Division.md: -------------------------------------------------------------------------------- 1 | # [399. Evaluate Division](https://leetcode.com/problems/evaluate-division/) 2 | 3 | TC: O(V+E), where E is the length of equations, V is at the same order of magnitude 4 | 5 | SC: O(V+E) 6 | ```java 7 | class Solution { 8 | record Node (String s, Double d) {} 9 | public double[] calcEquation(List> equations, double[] values, List> queries) { 10 | // create graph 11 | Map> graph = new HashMap<>(); 12 | for (int i = 0; i < values.length; i++) { 13 | List edge = equations.get(i); 14 | addEdge(graph, edge.get(0), edge.get(1), values[i]); 15 | addEdge(graph, edge.get(1), edge.get(0), 1 / values[i]); 16 | } 17 | 18 | // dfs graph 19 | double[] res = new double[queries.size()]; 20 | for (int i = 0; i < res.length; i++) { 21 | List q = queries.get(i); 22 | Set visited = new HashSet<>(); 23 | res[i] = graph.containsKey(q.get(0)) ? dfs(1, q.get(0), q.get(1), graph, visited) : -1; 24 | } 25 | 26 | return res; 27 | } 28 | 29 | private double dfs(double cost, String src, String dst, Map> graph, Set visited) { 30 | Double res = -1.0; 31 | if (!graph.containsKey(src)) return res; 32 | if (src.equals(dst)) return cost; 33 | 34 | for (Node node : graph.get(src)) { 35 | String next = node.s; 36 | if (visited.add(next)) { 37 | res = dfs(cost * node.d, next, dst, graph, visited); 38 | visited.remove(next); 39 | } 40 | if (!res.equals(-1.0)) break; 41 | } 42 | 43 | return res; 44 | } 45 | 46 | private void addEdge(Map> graph, String a, String b, double val) { 47 | List neis = graph.get(a); 48 | if (neis == null) graph.put(a, neis = new ArrayList<>()); 49 | neis.add(new Node(b, val)); 50 | } 51 | } 52 | ``` -------------------------------------------------------------------------------- /Solutions/Stack and Queue/853. Car Fleet.md: -------------------------------------------------------------------------------- 1 | # [853. Car Fleet](https://leetcode.com/problems/car-fleet/) 2 | ```java 3 | /* 4 | 计算每个车到达终点的时间 5 | 如果后面的比前面的车先到终点,那么后面的车一定会跟前面的车拖慢 6 | 所以根据每一个车input的位置和速度,可以计算出到达终点的时间 7 | 按照到达终点的时间从左往右扫描,做一个单调严格递减stack 8 | stack的size就是车队的数量 9 | 要先按照位置顺序排序 10 | 11 | case1: 12 | targe: 12 13 | pos: [10,8, 0,5,3] 14 | spd: [2,4, 1,1,3] 15 | after sort: 16 | [ 17 | Car[pos=0 , spd=1, ttd=12.0], 18 | Car[pos=3 , spd=3, ttd=3.0], 19 | Car[pos=5 , spd=1, ttd=7.0], 20 | Car[pos=8 , spd=4, ttd=1.0], 21 | Car[pos=10, spd=2, ttd=1.0]] 22 | 23 | stk: [12.0, 7.0, 1.0 <- (严格单调递减stack) 24 | ans: 3 (stk.size()) 25 | 26 | case2: 27 | targe: 10 28 | pos: [ 4, 6] 29 | spd: [ 3, 2] 30 | Converted: 31 | [ 32 | Car[pos=4, spd=3, ttd=2.0] 33 | Car[pos=6, spd=2, ttd=2.0]] 34 | stk: [2.0, (严格单调递减stack) 35 | ans: 1 (stk.size()) 36 | 37 | case3: 38 | targe: 10 39 | pos: [ 6, 8] 40 | spd: [ 3, 2] 41 | Converted: 42 | [ 43 | Car[pos=6, spd=3, ttd=1.3333333333333333], 44 | Car[pos=8, spd=2, ttd=1.0]] 45 | stk: [1.3333333333333333, 1.0 <- (严格单调递减stack) 46 | ans: 2 (stk.size()) 47 | 48 | 49 | case4: 50 | targe: 10 51 | pos: [ 0, 4, 2] 52 | spd: [ 2, 1, 3] 53 | Converted: 54 | [ 55 | Car[pos=0, spd=2, ttd=5.0], 56 | Car[pos=2, spd=3, ttd=2.6666666666666665], 57 | Car[pos=4, spd=1, ttd=6.0]] 58 | stk: [6.0, <- (严格单调递减stack) 59 | ans: 1 60 | */ 61 | class Solution { 62 | record Car(int pos, int spd, double ttd) {} // TTD: Time To reach Destination 63 | public int carFleet(int t, int[] pos, int[] spd) { 64 | int n = pos.length, top = -1; 65 | Car[] cars = new Car[n]; 66 | for (int i = 0; i < n; i++) cars[i] = new Car(pos[i], spd[i], ((double) t - pos[i])/spd[i]); 67 | Arrays.sort(cars, (a, b) -> a.pos - b.pos); // a - b could cause overflow, this is just for convenience 68 | double[] s = new double[n]; // nono-decreasing stack 69 | 70 | for (int i = 0; i < n; s[++top] = cars[i++].ttd) 71 | while (top >= 0 && (cars[i].ttd > s[top] || Math.abs(cars[i].ttd - s[top]) < .000001)) top--; 72 | 73 | return top + 1; 74 | } 75 | } 76 | ``` -------------------------------------------------------------------------------- /Solutions/Monotonic Stack/2104. Sum of Subarray Ranges.md: -------------------------------------------------------------------------------- 1 | # [2104. Sum of Subarray Ranges](https://leetcode.com/problems/sum-of-subarray-ranges/) 2 | 单调栈 3 |
 4 | 如何计算包含一个元素的所有subarray的数量:
 5 | 左边范围 * 右边范围
 6 | 比如:
 7 | value: 1 5 4 3 6 7 1
 8 | index: 0 1 2 3 4 5 6
 9 | 3作为最小值的所有subarray, 左边最多到0,右边到6(不包含):
10 | 所有起点: 5, 4, 3
11 | 所有终点: 3, 6, 7
12 | 左边3种可能,右边3种可能,3 * 3 = 9 种可能 in total,9中分别是:
13 | 5 4 3
14 | 5 4 3 6
15 | 5 4 3 6 7
16 |   4 3
17 |   4 3 6
18 |   4 3 6 7
19 |     3
20 |     3 6
21 |     3 6 7
22 | 
23 | TC/SC: O(n) 24 | ### Stack (11ms, 97.56%) 25 | ```java 26 | class Solution { 27 | public long subArrayRanges(int[] a) { 28 | int n = a.length, cur; 29 | long res = 0; 30 | Deque stack = new ArrayDeque<>(); 31 | stack.offerFirst(-1); 32 | 33 | for (int i = 0; i <= n; stack.offerFirst(i++)) 34 | while (stack.size() > 1 && (i == n || a[stack.peekFirst()] > a[i])) 35 | res -= (long) a[cur = stack.pollFirst()] * (cur - stack.peekFirst()) * (i - cur); 36 | 37 | stack.clear();stack.offerFirst(-1); 38 | for (int i = 0; i <= n; stack.offerFirst(i++)) 39 | while (stack.size() > 1 && (i == n || a[stack.peekFirst()] < a[i])) 40 | res += (long) a[cur = stack.pollFirst()] * (cur - stack.peekFirst()) * (i - cur); 41 | 42 | return res; 43 | } 44 | } 45 | ``` 46 | 47 | ### Array 无括号恶搞版 (3ms, 100%) 48 | ```java 49 | class Solution { 50 | public long subArrayRanges(int[] a) { 51 | int n = a.length, cur, top = -1; 52 | int[] s = new int[n]; // s: stack 53 | long res = 0; 54 | 55 | for (int i = 0; i <= n; s[++top] = i++) 56 | while (top >= 0 && (i == n || a[i] > a[s[top]])) 57 | res += (long) a[s[top]] * (i - s[top]) * (s[top] - (top-- == 0 ? -1 : s[top])); 58 | 59 | top = -1; // clear stack 60 | for (int i = 0; i <= n; s[++top] = i++) 61 | while (top >= 0 && (i == n || a[i] < a[s[top]])) 62 | res -= (long) a[s[top]] * (i - s[top]) * (s[top] - (top-- == 0 ? -1 : s[top])); 63 | 64 | return res; 65 | } 66 | } 67 | ``` -------------------------------------------------------------------------------- /Solutions/DP/1024. Video Stitching.md: -------------------------------------------------------------------------------- 1 | # [1024. Video Stitching](https://leetcode.com/problems/video-stitching/) 2 | 3 | Similar to Jump Game and 1326. Minimum Number of Taps to Open to Water a Garden 4 | ## BFS/greedy (1ms) 5 | TC: O(nlogn), SC: O(1) 6 | ```java 7 | class Solution { 8 | public int videoStitching(int[][] clips, int t) { 9 | Arrays.sort(clips, (a, b) -> a[0] - b[0]); 10 | int res = 0, n = clips.length; 11 | for (int curMax = 0, nextMax = 0, i = 0; curMax < t; res++, curMax = nextMax) { 12 | for (; i < n && clips[i][0] <= curMax; i++) { // get nextMax 13 | nextMax = Math.max(nextMax, clips[i][1]); 14 | if (nextMax >= t) return res + 1; 15 | } 16 | if (curMax == nextMax) return -1; 17 | } 18 | return res; 19 | } 20 | } 21 | ``` 22 | ## optimization, convert to jump game II 23 | TC: O(n), SC: O(n) 24 | 25 | ```java 26 | class Solution { 27 | public int videoStitching(int[][] clips, int t) { 28 | int[] a = new int[t]; 29 | for (var clip : clips) if (clip[0] < t) a[clip[0]] = Math.max(a[clip[0]], clip[1]); 30 | 31 | int res = 0; 32 | for (int curMax = 0, nextMax = 0, i = 0; curMax < t; res++, curMax = nextMax) { 33 | for (; i <= curMax; i++) { // get nextMax 34 | nextMax = Math.max(nextMax, a[i]); 35 | if (nextMax >= t) return res + 1; 36 | } 37 | if (curMax == nextMax) return -1; 38 | } 39 | return res; 40 | } 41 | } 42 | ``` 43 | 44 | ## Slightly different way 45 | ```java 46 | class Solution { 47 | public int videoStitching(int[][] clips, int t) { 48 | // convert to jump game II 49 | int[] a = new int[++t]; // we need to get to index t, so length is t+1: [0,t] 50 | for (var c : clips) if (c[0] < t) a[c[0]] = Math.max(a[c[0]], c[1]); 51 | 52 | int res = 0, curMax = 0; 53 | for (int i = 0, nextMax = 0; curMax >= i && nextMax < t - 1; res++, curMax = nextMax) 54 | while (i <= curMax) 55 | nextMax = Math.max(nextMax, a[i++]); 56 | 57 | return curMax < t - 1 ? -1 : res; 58 | } 59 | } 60 | ``` -------------------------------------------------------------------------------- /Solutions/Monotonic Stack/316. Remove Duplicate Letters.md: -------------------------------------------------------------------------------- 1 | # [316. Remove Duplicate Letters](https://leetcode.com/problems/remove-duplicate-letters/) 2 | Exactly the same as [1081. Smallest Subsequence of Distinct Characters](https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/) 3 | 4 | ## deque, 2ms, 99.32% 5 | TC: O(n), SC: O(n) 6 | ```java 7 | class Solution { 8 | public String removeDuplicateLetters(String s) { 9 | int n = s.length(); 10 | char[] a = s.toCharArray(); 11 | int[] lastIdx = new int[26]; 12 | for (int i = 0; i < n; i++) lastIdx[a[i] - 'a'] = i; 13 | 14 | Deque dq = new ArrayDeque<>(); 15 | boolean[] used = new boolean[26]; 16 | 17 | for (int i = 0; i < n; i++) { 18 | if (used[a[i] - 'a']) continue; // this letter already in deque 19 | while (!dq.isEmpty() && a[i] < dq.peekLast() && i < lastIdx[dq.peekLast() - 'a']) 20 | used[dq.pollLast() - 'a'] = false; 21 | dq.offerLast(a[i]); 22 | used[a[i] - 'a'] = true; 23 | } 24 | char[] res = new char[dq.size()]; 25 | for (int i = 0; i < res.length; i++) res[i] = dq.pollFirst(); 26 | return new String(res); 27 | } 28 | } 29 | ``` 30 | 31 | ## Array as stack/deque, 1ms, 100% 32 | TC: O(n), SC: O(n) 33 | ```java 34 | class Solution { 35 | public String removeDuplicateLetters(String s) { 36 | int n = s.length(), top = -1; // head and tail of dq 37 | char[] a = s.toCharArray(); 38 | boolean[] used = new boolean[26]; 39 | int[] last = new int[26]; // last index array 40 | char[] dq = new char[n]; // array to mimic dq/stack 41 | 42 | for (int i = 0; i < n; i++) last[a[i] - 'a'] = i; 43 | 44 | for (int i = 0; i < n; i++) { 45 | if (used[a[i] - 'a']) continue; // dup letters already in dq are ignored 46 | while (top >= 0 && a[i] < dq[top] && i < last[dq[top] - 'a']) 47 | used[dq[top--] - 'a'] = false; 48 | dq[++top] = a[i]; 49 | used[a[i] - 'a'] = true; 50 | } 51 | 52 | return new String(dq, 0, top + 1); 53 | } 54 | } 55 | ``` -------------------------------------------------------------------------------- /Solutions/GraphSearch/91. Array Hopper IV.md: -------------------------------------------------------------------------------- 1 | # [LaiCode 91. Array Hopper IV](https://app.laicode.io/app/problem/91) 2 | 3 | ## BFS 4 | TC: O(V+E), v = array.length, upper bound of E will be n^2, most of the time, the program should exit very early, but upper bound of TC will be: 5 | 6 | O(n^2) 7 | 8 | SC: O(n) (max size of the queue and steps array(array version of a de-dup map counting steps too)) 9 | ```java 10 | class Solution { 11 | public int minJump(int[] a, int idx) { 12 | Queue q = new ArrayDeque<>(); 13 | int[] steps = new int[a.length]; 14 | Arrays.fill(steps, -1); 15 | q.offer(idx); 16 | steps[idx] = 0; 17 | 18 | while (!q.isEmpty()) { 19 | int cur = q.poll(); 20 | if (cur == a.length - 1) break; 21 | 22 | for (int i = cur + 1; i <= Math.min(a.length - 1, cur + a[cur]); i++) 23 | if (steps[i] == -1) { 24 | steps[i] = steps[cur] + 1; 25 | q.offer(i); 26 | } 27 | 28 | for (int i = cur - 1; i >= Math.max(0, cur - a[cur]); i--) 29 | if (steps[i] == -1) { 30 | steps[i] = steps[cur] + 1; 31 | q.offer(i); 32 | } 33 | } 34 | 35 | return steps[a.length - 1]; 36 | } 37 | } 38 | ``` 39 | 40 | ## DFS? 41 | TC: O(n^2) DFS can't exit early, will traverse the whole graph for sure 42 | 43 | SC: O(n) 44 | 45 | ```java 46 | class Solution { 47 | public static int minJump(int[] array, int idx) { 48 | int n = array.length; 49 | int[] steps = new int[n]; 50 | Arrays.fill(steps, -1); 51 | dfs(array, idx, 0, steps); 52 | return steps[n - 1]; 53 | 54 | } 55 | 56 | public static void dfs(int[] arr, int idx, int count, int[] steps) { 57 | if (steps[idx] == -1) steps[idx] = count; 58 | else if (count < steps[idx]) steps[idx] = count; 59 | else return; // when count >= steps[idx], its not the first time we are here, exit(de-dup) 60 | if (idx == arr.length - 1) return; 61 | 62 | int right = Math.min(idx + arr[idx], arr.length - 1); 63 | int left = Math.max(0, idx - arr[idx]); 64 | for (int i = right; i >= left; i--) 65 | if (i != idx) 66 | dfs(arr, i, count + 1, steps); 67 | 68 | } 69 | } 70 | ``` -------------------------------------------------------------------------------- /Solutions/DP/740. Delete and Earn.md: -------------------------------------------------------------------------------- 1 | # [740. Delete and Earn](https://leetcode.com/problems/delete-and-earn/) 2 | 3 | ## Solution 0, DFS + MEMO 4 | ```java 5 | class Solution { 6 | public int deleteAndEarn(int[] a) { 7 | Arrays.sort(a); 8 | return dfs(0, a, new int[a.length]); // new int memo array 9 | } 10 | 11 | private int dfs(int idx, int[] a, int[] M) { 12 | if (idx == a.length) return 0; 13 | if (M[idx] > 0) return M[idx]; 14 | int cur = idx; 15 | int takeCur = a[cur++]; 16 | while (cur < a.length && a[cur] == a[idx]) { 17 | takeCur += a[idx]; 18 | cur++; 19 | } 20 | 21 | while (cur < a.length && a[cur] == a[idx]+1) cur++; 22 | takeCur += dfs(cur, a, M); 23 | int skipCur = dfs(idx+1, a, M); 24 | 25 | return M[idx] = Math.max(takeCur, skipCur); 26 | } 27 | } 28 | ``` 29 | ## Solution 1, DP 30 | ```java 31 | class Solution { 32 | public int deleteAndEarn(int[] a) { 33 | Arrays.sort(a); 34 | int n = a.length, keep = -1; 35 | int[] key = new int[n]; // count array 36 | int[] cnt = new int[n]; // count array 37 | 38 | for (int i = 0; i < n; ) { 39 | int start = i; 40 | while (i < n && a[start] == a[i]) i++; 41 | ++keep; 42 | key[keep] = a[start]; 43 | cnt[keep] = i - start; 44 | } 45 | 46 | int pre2 = 0, pre1 = 0, cur = 0, read = 0, i; 47 | for (i = key[0]; i <= key[keep]; i++, pre2 = pre1, pre1 = cur) { 48 | int score = i != key[read] ? 0 : cnt[read] * key[read++]; 49 | cur = Math.max(score + pre2, pre1); 50 | } 51 | 52 | return cur; 53 | } 54 | } 55 | ``` 56 | ## Solution 2, DP, space for time 57 | ```java 58 | class Solution { 59 | public int deleteAndEarn(int[] a) { 60 | int n = 10_001; 61 | int[] pts = new int[n]; 62 | for (int x : a) pts[x] += x; 63 | 64 | int cur = 0; 65 | for (int i = 2, p2 = pts[0], p1 = pts[1]; i < n; i++, p2 = p1, p1 = cur) 66 | cur = Math.max(pts[i] + p2, p1); 67 | 68 | return cur; 69 | } 70 | } 71 | ``` -------------------------------------------------------------------------------- /CanIWin.java: -------------------------------------------------------------------------------- 1 | /* 2 | There is an array of positive integers, in which each integer represents a piece of Pizza’s size, 3 | you and your friend take turns to pick pizza from either end of the array. 4 | The winner is the one who gets larger total sum of all pizza or whoever starts first if there is a tie. 5 | Return whether you will win the game if you start first. 6 | 7 | Example: 8 | Input: [2,1,100,3] 9 | Output: True 10 | 11 | Explanation: To win the game, you pick 2 first, then your friend will pick either 1 or 3, after that you could pick 100. 12 | In the end you could get 2 + 100 = 102, while your friend could only get 1 + 3 = 4. 13 | */ 14 | 15 | public class CanIWin { 16 | public boolean canWin(int[] p) { 17 | if (p.length == 0) return true; 18 | 19 | int len = p.length; 20 | int[][] dp = new int[len][len]; 21 | for (int diff = 0; diff < len; diff++) 22 | for (int i = 0; i + diff < len; i++) { 23 | int j = i + diff; 24 | if (i == j) dp[i][j] = p[i]; 25 | else if (j == i + 1) dp[i][j] = Math.max(p[i], p[j]); 26 | else { 27 | int pi = p[i] + Math.min(dp[i + 2][j], dp[i + 1][j - 1]); 28 | int pj = p[j] + Math.min(dp[i + 1][j - 1], dp[i][j - 2]); 29 | dp[i][j] = Math.max(pi, pj); 30 | } 31 | } 32 | 33 | int sum = 0; 34 | for (int value : p) sum += value; 35 | return dp[0][len - 1] >= sum - dp[0][len - 1]; 36 | } 37 | 38 | public static void main(String[] args) { 39 | CanIWin cw = new CanIWin(); 40 | int[] a1 = {1, 2, 100, 4, 3, 5, 6}; 41 | System.out.println(cw.canWin(a1)); //false 42 | int[] a2 = {55, 77, 73, 72, 9, 86, 35, 25, 53, 73, 100, 88, 89}; 43 | System.out.println(cw.canWin(a2)); // false 44 | int[] a3 = {7, 98, 5, 80, 35, 76}; 45 | System.out.println(cw.canWin(a3)); // true 46 | int[] a4 = {49,71,6,56,13,50,68,56,63,25,20,80,44,66,48,4,24}; 47 | System.out.println(cw.canWin(a4)); // false 48 | int[] a5 = {18,74,89,72,90,84,63,8,2,20,99,88,5}; 49 | System.out.println(cw.canWin(a5)); // false 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /SortInSpecifiedOrder.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | import java.util.Comparator; 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /* 7 | Given two integer arrays A1 and A2, sort A1 in such a way that the relative order among the elements will be same as those are in A2. 8 | For the elements that are not in A2, append them in the right end of the A1 in ascending order. 9 | Assumptions: 10 | A1 and A2 are both not null. 11 | There are no duplicate elements in A2. 12 | Examples: 13 | A1 = {2, 1, 2, 5, 7, 1, 9, 3}, A2 = {2, 1, 3}, A1 is sorted to {2, 2, 1, 1, 3, 5, 7, 9} 14 | */ 15 | public class SortInSpecifiedOrder { 16 | static class Comparator261 implements Comparator { 17 | private Map map; 18 | public Comparator261(int[] a) { 19 | map = new HashMap<>(); 20 | for (int i = 0; i < a.length; i++) map.put(a[i], i); 21 | } 22 | @Override 23 | public int compare(Integer i1, Integer i2) { 24 | Integer idx1 = map.get(i1); 25 | Integer idx2 = map.get(i2); 26 | if (idx1 != null && idx2 != null) return idx1.compareTo(idx2); 27 | if (idx1 == null && idx2 == null) return i1.compareTo(i2); 28 | return idx1 != null ? -1 : 1; 29 | } 30 | } 31 | 32 | public Integer[] toInteger(int[] a) { 33 | Integer[] res = new Integer[a.length]; 34 | for (int i = 0; i < a.length; i++) res[i] = a[i]; 35 | return res; 36 | } 37 | 38 | public int[] toInt(Integer[] a) { 39 | int[] res = new int[a.length]; 40 | for (int i = 0; i < a.length; i++) res[i] = a[i]; 41 | return res; 42 | } 43 | 44 | public int[] sortSpecial(int[] a1, int[] a2) { // O(m + n) 45 | Integer[] a1i = toInteger(a1); 46 | Arrays.sort(a1i, new Comparator261(a2)); 47 | return toInt(a1i); 48 | } 49 | 50 | public static void main(String[] args) { 51 | int[] a1 = new int[]{2, 1, 2, 5, 7, 1, 9, 3}; 52 | int[] a2 = new int[]{2, 1, 3}; 53 | SortInSpecifiedOrder sso = new SortInSpecifiedOrder(); 54 | System.out.println(Arrays.equals(sso.sortSpecial(a1, a2), new int[]{2, 2, 1, 1, 3, 5, 7, 9})); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Solutions/String and Array/484. Find Permutation.md: -------------------------------------------------------------------------------- 1 | # [484. Find Permutation](https://leetcode.com/problems/find-permutation/) 2 | Almost the same as [2375. Construct Smallest Number From DI String](https://leetcode.com/problems/construct-smallest-number-from-di-string/) 3 | ## Swap, 2ms, 100%; 4 | TC:O(n), SC: O(1) 5 | ```java 6 | class Solution { 7 | public int[] findPermutation(String s) { 8 | int n = s.length(), count = 0; 9 | int[] res = new int[n+1]; 10 | for (int i = 0; i <= n; i++) res[i] = i+1; // increasing 11 | 12 | for (int i = 0; i < n;) { 13 | if (s.charAt(i) == 'D') { 14 | int start = i; 15 | while (i < n && s.charAt(i) == 'D') i++; 16 | swap(res, start, i); 17 | } else i++; 18 | } 19 | return res; 20 | } 21 | 22 | private void swap(int[] a, int i, int j) { 23 | while (i < j) { 24 | int x = a[i]; 25 | a[i++] = a[j]; 26 | a[j--] = x; 27 | } 28 | } 29 | } 30 | ``` 31 | ## use stack 32 | TC/SC: O(n) 33 | ```java 34 | class Solution { 35 | public int[] findPermutation(String s) { 36 | int n = s.length(), top = -1; 37 | int[] stk = new int[n+1], res = new int[n+1]; 38 | 39 | int j = 0; 40 | for (int i = 1; i <= n; i++) { 41 | if (s.charAt(i-1) == 'I') { 42 | res[j++] = i; 43 | while (top >= 0) res[j++] = stk[top--]; 44 | } else stk[++top] = i; 45 | } 46 | res[j++] = n+1; 47 | while (top >= 0) res[j++] = stk[top--]; 48 | return res; 49 | } 50 | } 51 | ``` 52 | ## count D and fill, 3ms, 90.43% 53 | TC/SC: O(n) 54 | ```java 55 | class Solution { 56 | public int[] findPermutation(String pat) { 57 | int n = pat.length(), max = n+1, cur = n; 58 | int[] p = new int[n+1]; 59 | for (int i = 0; i < n; i++) if (pat.charAt(i) == 'D') p[i+1] = p[i] + 1; 60 | int[] a = new int[n+1]; 61 | 62 | for (int i = n; i >= 0; i--, cur--) 63 | if (p[i] > 0) a[i] = max - p[i]; 64 | else { 65 | a[i] = max; 66 | max = cur; 67 | } 68 | 69 | return a; 70 | } 71 | } 72 | ``` -------------------------------------------------------------------------------- /Tree/DistanceOfTwoNodesInBinaryTree.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | /* 3 | Find distance between two given keys of a Binary Tree, no parent pointers are given. 4 | Distance between two nodes is the minimum number of edges to be traversed to reach one node from others. 5 | 6 | Assumptions: 7 | There are no duplicate keys in the binary tree. 8 | The given two keys are guaranteed to be in the binary tree. 9 | The given two keys are different. 10 | 11 | Examples: 12 | 1 13 | / \ 14 | 2 3 15 | / \ / \ 16 | 4 5 6 7 17 | \ 18 | 8 19 | distance(4, 5) = 2 20 | distance(4, 6) = 4 21 | */ 22 | 23 | import util.TreeNode; 24 | 25 | public class DistanceOfTwoNodesInBinaryTree { 26 | public int distance(TreeNode root, int k1, int k2) { // TC: O(2n)--> O(n), SC: O(height) 27 | TreeNode lca = lca(root, k1, k2); 28 | return depth(lca, k1, 0) + depth(lca, k2, 0); 29 | } 30 | 31 | public TreeNode lca(TreeNode root, int k1, int k2) { // TC: O(n), SC: O(height) 32 | if (root == null || root.key == k1 || root.key == k2) return root; 33 | TreeNode left = lca(root.left, k1, k2); 34 | TreeNode right = lca(root.right, k1, k2); 35 | if (left != null && right != null) return root; 36 | return left != null ? left : right; 37 | } 38 | 39 | public int depth(TreeNode root, int k, int depth) { // TC: O(n), SC: O(height) 40 | if (root == null) return -1; 41 | if (root.key == k) return depth; 42 | int left = depth(root.left, k, depth + 1); 43 | int right = depth(root.right, k, depth + 1); 44 | return left != -1 ? left : right; 45 | } 46 | 47 | public static void main(String[] args) { 48 | DistanceOfTwoNodesInBinaryTree dtb = new DistanceOfTwoNodesInBinaryTree(); 49 | TreeNode root = TreeNode.fromLevelOrder(new Integer[]{7, 13, -9, 101, 5, 8, 10, null, 2, 4, 6}); 50 | TreeNode root2 = TreeNode.fromLevelOrder(new Integer[]{1, 2, 3, 4, 5, 6, 7, null, null, null, 8}); 51 | System.out.println(root2); 52 | System.out.println(dtb.distance(root, 10, 4)); // 5 53 | System.out.println(dtb.distance(root2, 5, 4)); // 2 54 | System.out.println(dtb.distance(root2, 6, 4)); // 4 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /WordSearch.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given a 2D board and a word, find if the word exists in the grid. 3 | The word can be constructed from letters of sequentially adjacent cell, 4 | where "adjacent" cells are those horizontally or vertically neighboring. 5 | The same letter cell may not be used more than once. 6 | 7 | Input: board = [ 8 | [“ABCE”], 9 | [“SFCS”], 10 | [“ADEE”] 11 | ] 12 | 13 | Output: Word = “ABCCED” return true 14 | Word = “SEE” return true 15 | Word = “ABCB” return false 16 | */ 17 | 18 | public class WordSearch { 19 | public final int[][] dirs = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, }; 20 | private int rows, cols; 21 | public boolean isWord(char[][] board, String s) { 22 | if ((rows = board.length) == 0 || (cols = board[0].length) == 0) return false; 23 | 24 | boolean[][] visited = new boolean[rows][cols]; 25 | for (int i = 0; i < rows; i++) 26 | for (int j = 0; j < cols; j++) 27 | if (dfs(0, s.toCharArray(), i, j, board, visited)) return true; 28 | 29 | return false; 30 | } 31 | 32 | private boolean dfs(int idx, char[] a, int i, int j, char[][] board, boolean[][] visited) { 33 | if (idx == a.length) return true; 34 | if (i < 0 || j < 0 || i >= rows || j >= cols || visited[i][j] || board[i][j] != a[idx]) 35 | return false; 36 | 37 | visited[i][j] = true; 38 | for (int[] dir : dirs) 39 | if (dfs(idx + 1, a, i + dir[0], j + dir[1], board, visited)) return true; 40 | visited[i][j] = false; 41 | 42 | return false; 43 | } 44 | 45 | public static void main(String[] args) { 46 | WordSearch ws = new WordSearch(); 47 | char[][] b0 = new char[][] { 48 | {'A'}, 49 | }; 50 | System.out.println(ws.isWord(b0, "A")); // true 51 | char[][] b1 = new char[][] { 52 | {'A','B','C','E'}, 53 | {'S','F','C','S'}, 54 | {'A','D','E','E'} 55 | }; 56 | System.out.println(ws.isWord(b1,"ABCCED")); // true 57 | System.out.println(ws.isWord(b1,"SEE")); // true 58 | System.out.println(ws.isWord(b1,"ABCB")); // false 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /Solutions/String and Array/1249. Minimum Remove to Make Valid Parentheses.md: -------------------------------------------------------------------------------- 1 | # [1249. Minimum Remove to Make Valid Parentheses](https://leetcode.com/problems/minimum-remove-to-make-valid-parentheses/) 2 | 3 | ## count 4 | TC: O(n), SC: O(1) or you could say O(n) 5 | 6 | ```java 7 | class Solution { 8 | public String minRemoveToMakeValid(String s) { 9 | int n = s.length(), end = 0, count = 0; 10 | char[] a = new char[n]; 11 | 12 | for (int i = 0; i < n; i++) { 13 | char c = s.charAt(i); 14 | if (c == '(') count++; 15 | else if (c == ')') { 16 | if (count == 0) continue; // an additional ), skip it 17 | count--; 18 | } 19 | a[end++] = c; // copy every valid char 20 | } 21 | 22 | count = 0; 23 | int start = end - 1; 24 | for (int i = end - 1; i >= 0; i--) { 25 | char c = a[i]; // now we read from array, all invalid ) has been removed 26 | if (c == ')') count++; 27 | else if (c == '(') { 28 | if (count == 0) continue; // an additional (, skip it 29 | count--; 30 | } 31 | a[start--] = c; // copy every valid char 32 | } 33 | 34 | return new String(a, start + 1, end - start - 1); 35 | } 36 | } 37 | ``` 38 | 39 | ## array as deque/stack 40 | TC: O(n), SC: O(n) 41 | ```java 42 | class Solution { 43 | public String minRemoveToMakeValid(String str) { 44 | int n = str.length(), top = -1; 45 | int[] s = new int[n]; // stack to keep all index of invalid brackets 46 | 47 | for (int i = 0; i < n; i++) { 48 | char c = str.charAt(i); 49 | if (c == '(') s[++top] = i; 50 | else if (c == ')') { 51 | if (top >= 0 && str.charAt(s[top]) == '(') top--; 52 | else s[++top] = i; 53 | } 54 | } 55 | 56 | if (top < 0) return str; 57 | 58 | char[] a = new char[n - top - 1]; // write string to char[], skip all invalids 59 | for (int i = 0, keep = 0, j = 0; i < n; i++) { 60 | if (j <= top && s[j] == i) j++; 61 | else a[keep++] = str.charAt(i); 62 | } 63 | 64 | return new String(a); 65 | } 66 | } 67 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/1166. Design File System.md: -------------------------------------------------------------------------------- 1 | # [1166. Design File System](https://leetcode.com/problems/design-file-system/) 2 | 3 | ## No split, 85ms, 99.81% 4 | ```java 5 | class FileSystem { 6 | Map map = new HashMap<>(); 7 | public FileSystem () { 8 | map.put("", -1); 9 | } 10 | 11 | public boolean createPath(String path, int x) { 12 | if (!map.containsKey(path.substring(0, path.lastIndexOf('/')))) 13 | return false; 14 | return map.putIfAbsent(path, x) == null; // path already exist 15 | } 16 | 17 | public int get(String path) { 18 | return map.getOrDefault(path, -1); 19 | } 20 | } 21 | 22 | /** 23 | * Your FileSystem object will be instantiated and called as such: 24 | * FileSystem obj = new FileSystem(); 25 | * boolean param_1 = obj.createPath(path,value); 26 | * int param_2 = obj.get(path); 27 | */ 28 | ``` 29 | ## 106ms, 94.28% 30 | ```java 31 | class File { // both file and directories are considered file 32 | Map files = new HashMap<>(); 33 | int val; 34 | public File(int x) { 35 | val = x; 36 | } 37 | } 38 | 39 | class FileSystem { 40 | File root = new File(-1); 41 | 42 | public boolean createPath(String path, int x) { 43 | String[] a = path.split("/"); 44 | File cur = root; 45 | for (int i = 1; i < a.length; i++) { 46 | File next = cur.files.get(a[i]); 47 | if (next == null) { 48 | if (i == a.length-1) { 49 | cur.files.put(a[i], new File(x)); 50 | return true; 51 | } 52 | return false; 53 | } 54 | cur = next; 55 | } 56 | return false; 57 | } 58 | 59 | public int get(String path) { 60 | String[] a = path.split("/"); 61 | File cur = root; 62 | for (int i = 1; i < a.length; i++) { 63 | File next = cur.files.get(a[i]); 64 | if (next == null) return -1; 65 | cur = next; 66 | } 67 | return cur.val; 68 | } 69 | } 70 | 71 | /** 72 | * Your FileSystem object will be instantiated and called as such: 73 | * FileSystem obj = new FileSystem(); 74 | * boolean param_1 = obj.createPath(path,value); 75 | * int param_2 = obj.get(path); 76 | */ 77 | ``` -------------------------------------------------------------------------------- /Solutions/DP/1092. Shortest Common Supersequence.md: -------------------------------------------------------------------------------- 1 | # [1092. Shortest Common Supersequence](https://leetcode.com/problems/shortest-common-supersequence/) 2 | 3 | ## on top of 1143 dp, 9ms, 99.79% 4 | TC: O(m * n), SC: O(m * n) 5 | 6 | reuse work from [1143. Longest Common Subsequence](https://leetcode.com/problems/longest-common-subsequence/) 7 | ```java 8 | class Solution { 9 | public String shortestCommonSupersequence(String s1, String s2) { 10 | char[] a = s1.toCharArray(), b = s2.toCharArray(); 11 | int m = a.length, n = b.length; 12 | 13 | char[] lcs = getLCS(a, b); // get lcs in char[] 14 | char[] d = new char[m + n - lcs.length]; // d is final result 15 | int i = 0, j = 0, k = 0; 16 | for (char c : lcs) { 17 | while (a[i] != c) d[k++] = a[i++]; // copy non-common chars from a 18 | while (b[j] != c) d[k++] = b[j++]; // copy non-common chars from b 19 | d[k++] = c;i++;j++; // common chars only copied once while i,j both moves 20 | } 21 | while (i < m) d[k++] = a[i++]; // copy leftover non-common chars from a 22 | while (j < n) d[k++] = b[j++]; // copy leftover non-common chars from b 23 | 24 | return new String(d); 25 | } 26 | 27 | private char[] getLCS(char[] a, char[] b) { 28 | // first part is the same as 1143. Longest Common Subsequence 29 | // we need the fullsized dp matrix 30 | int m = a.length, n = b.length; 31 | int[][] dp = new int[m+1][n+1]; 32 | 33 | for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) { 34 | if (a[i] == b[j]) dp[i+1][j+1] = dp[i][j] + 1; // lcs are only increased on diagonal 35 | else dp[i+1][j+1] = Math.max(dp[i][j+1], dp[i+1][j]); 36 | } 37 | // now we have the dp matrix, let's construct lcs 38 | char[] lcs = new char[dp[m][n]]; 39 | int i = m, j = n, k = lcs.length - 1; // k pointer for filling lcs backwards 40 | while (i > 0 && j > 0) { 41 | if (dp[i][j] == dp[i-1][j]) i--;// dp[i][j] != dp[i-1][j] for sure when a[i-1]==b[j-1] 42 | else if (dp[i][j] == dp[i][j-1]) j--; 43 | else { 44 | lcs[k--] = a[--i]; // i started from m, so we decrease it first 45 | j--; 46 | } 47 | } 48 | 49 | return lcs; 50 | } 51 | } 52 | ``` -------------------------------------------------------------------------------- /Solutions/DP/552. Student Attendance Record II.md: -------------------------------------------------------------------------------- 1 | # [552. Student Attendance Record II](https://leetcode.com/problems/student-attendance-record-ii/) 2 | 3 | ## Solution 1, DFS with memo 4 | not so fast, easy to understanding 5 | 6 | TC/SC: (2 * 3 * n) 7 | ```java 8 | class Solution { 9 | int M = 1_000_000_007; 10 | public int checkRecord(int n) { 11 | return dfs(0, 0, 0, n, new int[2][3][n]); // we have 3 variables(how many As so far, how many consecutive Ls, cur length), so 3d memo 12 | } 13 | 14 | private int dfs(int A, int L, int len, int n, int[][][] cache) { 15 | if (A > 1 || L > 2) return 0; // invalid options 16 | if (len == n) return 1; // filled one n length choices 17 | if (cache[A][L][len] > 0) return cache[A][L][len]; 18 | 19 | int res = 0; 20 | res = (res + dfs(A+1, 0, len+1, n, cache)) % M;// 今天决定迟到, L就被reset了 21 | res = (res + dfs(A, L+1, len+1, n, cache)) % M;// 今天决定晚到 22 | res = (res + dfs(A , 0, len+1, n, cache)) % M; // 还是乖乖按时到吧, L又被reset了 23 | 24 | return cache[A][L][len] = res; 25 | } 26 | } 27 | ``` 28 | ## Solution 2, DP, 54ms, 94.81% 29 | TC/SC: O(n) 30 | ```java 31 | class Solution { 32 | int M = 1_000_000_007; 33 | public int checkRecord(int n) { 34 | int[] p = new int[n+1]; // cur length end with p 35 | int[] l = new int[n+1]; // cur length end with L 36 | 37 | p[0] = p[1] = l[1] = 1; // p[1]=1: P, l[1]=1: L, p[0] = 1 is for corner case l[2]=p[1]+p[0] = 2 38 | for (int i = 2; i <= n; i++) { // we don't consider A yet 39 | p[i] = (p[i-1] + l[i-1]) % M; // we add a P to i-1 length end with P or L 40 | l[i] = (p[i-1] + p[i-2]) % M; // we add one L to p[i-1], or add LL to p[i-2] 41 | } 42 | 43 | long res = (p[n] + l[n]) % M; // res's all possible choices without A 44 | // now let's insert the A at all possible places 45 | // where we insert A, the split are split into two parts with combined length of n-1 46 | // similar to 907, 1856 and 2104, left choices * right choices is the total choices when we insert A any where inside the string 47 | for (int i = 0; i < n; i++) 48 | res = (res + (long) ((p[i] + l[i]) % M) * ((p[n-i-1]+l[n-i-1]) % M)) % M; 49 | 50 | return (int) res; 51 | } 52 | } 53 | ``` -------------------------------------------------------------------------------- /FactorCombinations.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given an integer number, return all possible combinations of the factors that can multiply to the target number. 3 | 4 | Example 5 | 6 | Give A = 24 7 | since 24 = 2 x 2 x 2 x 3 8 | = 2 x 2 x 6 9 | = 2 x 3 x 4 10 | = 2 x 12 11 | = 3 x 8 12 | = 4 x 6 13 | 14 | your solution should return 15 | { { 2, 2, 2, 3 }, { 2, 2, 6 }, { 2, 3, 4 }, { 2, 12 }, { 3, 8 }, { 4, 6 } } 16 | 17 | note: duplicate combination is not allowed. 18 | */ 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | public class FactorCombinations { 24 | public List> combinations(int target) { 25 | List> res = new ArrayList<>(); 26 | List cur = new ArrayList<>(); 27 | List factors = getFactors(target, new ArrayList<>()); 28 | dfs(0, target, cur, factors, res); 29 | return res; 30 | } 31 | 32 | private void dfs(int idx, int target, List cur, List factors, List> res) { 33 | if (idx == factors.size()) { 34 | if (target == 1) res.add(new ArrayList<>(cur)); 35 | return; 36 | } 37 | 38 | dfs(idx + 1, target, cur, factors, res); // this has to execute first, as after below for loop, target = 1 39 | int factor = factors.get(idx); 40 | int size = cur.size(); 41 | while (target % factor == 0) { 42 | cur.add(factor); 43 | dfs(idx + 1, target /= factor, cur, factors, res); 44 | } 45 | cur.subList(size, cur.size()).clear(); 46 | } 47 | 48 | public List getFactors(int target, List factors) { 49 | for (int i = 2; i <= target / 2; i++) 50 | if (target % i == 0) factors.add(i); 51 | return factors; 52 | } 53 | 54 | public static void main(String[] args) { 55 | FactorCombinations fc = new FactorCombinations(); 56 | System.out.println(fc.getFactors(100, new ArrayList<>())); // [2, 4, 5, 10, 20, 25, 50] 57 | 58 | System.out.println(fc.combinations(24)); // [[4, 6], [3, 8], [2, 12], [2, 3, 4], [2, 2, 6], [2, 2, 2, 3]] 59 | System.out.println(fc.combinations(100)); // [[10, 10], [5, 20], [4, 25], [4, 5, 5], [2, 50], [2, 5, 10], [2, 2, 25], [2, 2, 5, 5]] 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Solutions/DP/1312. Minimum Insertion Steps to Make a String Palindrome.md: -------------------------------------------------------------------------------- 1 | # [1312. Minimum Insertion Steps to Make a String Palindrome](https://leetcode.com/problems/minimum-insertion-steps-to-make-a-string-palindrome/) 2 | 3 | ## 1d DP, exact solution from 516 4 | TC: O(n^2), SC: O(n) 5 | ```java 6 | class Solution { 7 | public int minInsertions(String s) { 8 | int max = 0, n = s.length(); 9 | char[] a = s.toCharArray(); 10 | int[] dp = new int[n]; 11 | Arrays.fill(dp, 1); 12 | 13 | for (int j = 1; j < n; j++, max = 0) for (int i = j - 1; i >= 0; i--) { 14 | int pre = dp[i]; // best from cur i to prev j 15 | if (a[i] == a[j]) dp[i] = 2 + max; 16 | if (pre > max) max = pre; // update max for next j to use 17 | } 18 | 19 | for (int x : dp) if (x > max) max = x; 20 | return n - max; 21 | } 22 | } 23 | ``` 24 | ## Recursion + memo, 18ms, 98.57% 25 | TC: O(n^2), SC: O(n^2) 26 | ```java 27 | class Solution { 28 | public int minInsertions(String s) { 29 | int n = s.length(); 30 | Integer[][] dp = new Integer[n][n]; 31 | return dfs(s.toCharArray(), 0, n - 1, dp); // matching from both sides 32 | } 33 | 34 | private int dfs(char[] a, int i, int j, Integer[][] dp) { 35 | if (dp[i][j] != null) return dp[i][j]; 36 | if (i >= j) return dp[i][j] = 0; 37 | 38 | if (a[i] == a[j]) 39 | return dp[i][j] = dfs(a, i+1, j-1, dp); 40 | return dp[i][j] = Math.min(dfs(a, i+1, j, dp), dfs(a, i, j-1, dp)) + 1; // insert 1 to the left or right 41 | } 42 | } 43 | ``` 44 | 45 | ## dp, 12ms, 99.74% 46 | TC: O(n^2), SC: O(n^2) 47 | ```java 48 | class Solution { 49 | public int minInsertions(String s) { 50 | char[] a = s.toCharArray(); 51 | int n = a.length; 52 | int[][] dp = new int[n][n]; 53 | 54 | // find the longest common palindrome first 55 | // [i, j] is the sub-problem of substring [i, j] 56 | for (int j = 0; j < n; j++) for (int i = j; i >= 0; i--) { 57 | if (i == j) dp[i][j] = 1; 58 | else if (a[i] == a[j]) dp[i][j] = dp[i+1][j-1] + 2; 59 | else dp[i][j] = Math.max(dp[i+1][j], dp[i][j-1]); 60 | } 61 | 62 | return n - dp[0][n - 1]; // the result is total length of string - LCP 63 | } 64 | } 65 | ``` -------------------------------------------------------------------------------- /Solutions/Misc/975. Odd Even Jump.md: -------------------------------------------------------------------------------- 1 | # [975. Odd Even Jump](https://leetcode.com/problems/odd-even-jump/) 2 | 3 | ## 单调栈, Monotonic Stack (45ms, 99.38%) 4 | TC: O(nlogn) (two sorts), scL O(n) 5 | ```java 6 | class Solution { 7 | public int oddEvenJumps(int[] arr) { 8 | int n = arr.length; 9 | int[][] mx = new int[n][2]; 10 | for (int i = 0; i < n; i++) mx[i] = new int[]{i, arr[i]}; // idx vs val 11 | 12 | Arrays.sort(mx, (a, b) -> a[1] == b[1] ? a[0] - b[0] : a[1] - b[1]); 13 | int[] odd = new int[n]; 14 | Arrays.fill(odd, -1); 15 | 16 | int[] s = new int[n]; 17 | int top = -1; 18 | for (int i = 0; i < n; s[++top] = mx[i++][0]) 19 | while (top >= 0 && mx[i][0] > s[top]) 20 | odd[s[top--]] = mx[i][0]; 21 | 22 | Arrays.sort(mx, (a, b) -> a[1] == b[1] ? a[0] - b[0] : b[1] - a[1]); 23 | int[] even = new int[n]; 24 | Arrays.fill(even, -1); 25 | 26 | top = -1; 27 | for (int i = 0; i < n; s[++top] = mx[i++][0]) 28 | while (top >= 0 && mx[i][0] > s[top]) 29 | even[s[top--]] = mx[i][0]; 30 | 31 | boolean[][] dp = new boolean[n][2]; 32 | dp[n - 1][0] = dp[n - 1][1] = true; //even 0, odd 1 33 | 34 | int cnt = 1; 35 | for (int i = n - 2; i >= 0; i--) { 36 | dp[i][0] = even[i] != -1 && dp[even[i]][1]; 37 | dp[i][1] = odd[i] != -1 && dp[odd[i]][0]; 38 | 39 | if (dp[i][1]) cnt++; 40 | } 41 | 42 | return cnt; 43 | } 44 | } 45 | ``` 46 | 47 | ## TreeMap (66ms, 97.43%) 48 | TC: O(nlogn), SC: O(n) 49 | ```java 50 | class Solution { 51 | public int oddEvenJumps(int[] a) { 52 | int n = a.length, res = 1; 53 | boolean[] hig = new boolean[n], low = new boolean[n]; 54 | hig[n - 1] = low[n - 1] = true; 55 | 56 | TreeMap map = new TreeMap<>(); 57 | map.put(a[n - 1], n - 1); 58 | 59 | for (int i = n - 2; i >= 0; i--) { 60 | Map.Entry hi = map.ceilingEntry(a[i]), lo = map.floorEntry(a[i]); 61 | if (hi != null) hig[i] = low[hi.getValue()]; 62 | if (lo != null) low[i] = hig[lo.getValue()]; 63 | if (hig[i]) res++; 64 | map.put(a[i], i); 65 | } 66 | 67 | return res; 68 | } 69 | } 70 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/291. Ternary Expression Tree.md: -------------------------------------------------------------------------------- 1 | # [LaiCode 291. Ternary Expression Tree](https://app.laicode.io/app/problem/291) 2 | 3 | ## 什么是 Ternary Expression Tree 4 | 就是Java(其他语言也有啦)里面的三元运算符: 5 | 6 | int val = 7 | 8 | a == b ? x : y; 9 | 10 | 上面就是一个三元运算的完整语句, 他的特点是每个node要么是leaf要么有2个孩子,不会只有一个孩子, 因为❓后面的冒号前后的两个选择也一个都不能少, 不然compiler会报错。 11 | 然后x和y两个位置可以被完整的三元运算语句(递归的)替换。 12 | 13 | 这一题真正的意义是模拟compiler在编译时给三元运算符建一个evaluation树,在运行时,根据每一个node是true还是false从建好的evaluation树的root沿着一个直上直下的路径往下执行,最终找到结果(一个叶子结点)。 14 | 15 | ## Solution 1: Iterative 16 | TC: O(n) 17 | 18 | SC: O(height) (size in stack) 19 | 20 | 1. 前面如果是❓,说明当前node是前面node的左node 21 | 2. 前面如果是':',说明当前node是之前node的右node 22 | 1. 连完右node,就可以把爸爸poll出来了(左右都练好了不出来还想干嘛?) 但这个node本身要不要放进去要看后面是什么符号。 23 | 3. 后面如果是❓, 说明当前node不是leaf node, 要offer到stack里面(等着接自己的孩子) 24 | 1. 后面是':'那么当前node是leaf node, 连完父母就结束什么也不用做,不用offer 25 | ```java 26 | class Solution { 27 | public ExpNode tree(String s) { 28 | if (s == null || s.length() == 0) return null; 29 | ExpNode root = new ExpNode(s.charAt(0)); 30 | Deque stack = new ArrayDeque<>(); 31 | stack.offerFirst(root); 32 | 33 | for (int i = 2; i < s.length(); i+=2) { 34 | ExpNode node = new ExpNode(s.charAt(i)); 35 | 36 | if (s.charAt(i - 1) == '?') 37 | stack.peekFirst().left = node; 38 | else stack.pollFirst().right = node; 39 | 40 | if (i + 1 < s.length() && s.charAt(i + 1) == '?') 41 | stack.offerFirst(node); 42 | } 43 | 44 | return root; 45 | } 46 | } 47 | ``` 48 | 49 | ## Solution 2: Recursion 50 | input很容易看出来是我们要建的tree的preOrder traversal的结果,所以用preOrder递归的去建树就可以了。 51 | 52 | 建树的时候要注意,碰到下面一个是❓,那么需要给他建左右子树,否则的话就是个leaf node了,把自己返回就行了。 53 | 54 | 因为最后两个node一定是leaf,所以其实不需要base case,main logic就会终止recursion逻辑。 55 | TC: O(n) 56 | 57 | SC: O(height) call stack usage 58 | ```java 59 | class Solution { 60 | int idx; 61 | public ExpNode tree(String s) { 62 | if (s == null || s.length() == 0) return null; 63 | idx = 0; // better-practice to initialize it here 64 | return dfs(s); 65 | } 66 | 67 | private ExpNode dfs(String s) { 68 | ExpNode root = new ExpNode(s.charAt(idx)); // preOrder! 69 | 70 | if ((idx += 2) - 1 < s.length() && s.charAt(idx - 1) == '?') { 71 | root.left = dfs(s); 72 | root.right = dfs(s); 73 | } 74 | 75 | return root; 76 | } 77 | } 78 | ``` -------------------------------------------------------------------------------- /TotalOccurrence.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given a target integer T and an integer array A sorted in ascending order, Find the total number of occurrences of T in A. 3 | Examples 4 | A = {1, 2, 3, 4, 5}, T = 3, return 1 5 | A = {1, 2, 2, 2, 3}, T = 2, return 3 6 | A = {1, 2, 2, 2, 3}, T = 4, return 0 7 | Corner Cases 8 | What if A is null? We should return 0 in this case. 9 | */ 10 | public class TotalOccurrence { 11 | // Solution 2 starts here 12 | // TC: O(log(n) + count) 13 | // SC: O(1) 14 | public int totalOccurrence2(int[] a, int T) { 15 | if (a == null || a.length == 0) return 0; 16 | int l = 0, r = a.length - 1, m = 0; 17 | while (l <= r) { 18 | m = l + (r - l) / 2; 19 | if (a[m] == T) break; 20 | else if (a[m] < T) l = m + 1; 21 | else r = m - 1; 22 | } 23 | 24 | int count = 0; 25 | for (l = m; l >= 0 && a[l] == T; l--) count++; 26 | for (r = m + 1; r < a.length && a[r] == T; r++) count++; 27 | return count; 28 | } 29 | // Solution 2 ends here 30 | 31 | // Solution 1 starts here 32 | // TC: O(2*log(n)) 33 | // SC: O(1) 34 | public int totalOccurrence(int[] a, int T) { 35 | if (a == null || a.length == 0) return 0; 36 | int l = firstOccur(a, T); 37 | if (l == -1) return 0; // T do not exist 38 | return lastOccur(a, T) - l + 1; 39 | } 40 | 41 | private int firstOccur(int[] a, int T) { 42 | int l = 0, r = a.length - 1; 43 | while (l < r - 1) { 44 | int m = l + (r - l) / 2; 45 | if (a[m] < T) l = m; 46 | else r = m; 47 | } 48 | return a[l] == T ? l : a[r] == T ? r : -1; 49 | } 50 | 51 | private int lastOccur(int[] a, int T) { 52 | int l = 0, r = a.length - 1; 53 | while (l < r - 1) { 54 | int m = l + (r - l) / 2; 55 | if (a[m] <= T) l = m; 56 | else r = m; 57 | } 58 | return a[r] == T ? r : a[l] == T ? l : -1; 59 | } 60 | // Solution 1 ends here 61 | public static void main(String[] args) { 62 | TotalOccurrence to = new TotalOccurrence(); 63 | System.out.println(to.totalOccurrence2(new int[]{1, 2, 2, 2, 4, 5, 8, 13, 13}, 13) == 2); 64 | System.out.println(to.totalOccurrence(new int[]{1, 2, 2, 2, 4, 5, 8, 13, 13}, 13) == 2); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /AllValidPermutationsOfParenthesesII.java: -------------------------------------------------------------------------------- 1 | /* 2 | Get all valid permutations of l pairs of (), m pairs of <> and n pairs of {}. 3 | 4 | Assumptions 5 | l, m, n >= 0 6 | l + m + n > 0 7 | 8 | Examples 9 | l = 1, m = 1, n = 0, all the valid permutations are ["()<>", "(<>)", "<()>", "<>()"] 10 | */ 11 | 12 | import java.util.ArrayDeque; 13 | import java.util.ArrayList; 14 | import java.util.Deque; 15 | import java.util.List; 16 | 17 | public class AllValidPermutationsOfParenthesesII { // TC: O(2^2*(l+m+n)), SC: O(2*(l+m+n)) 18 | char[] p = new char[] {'(', ')', '<', '>', '{', '}'}; // pick array 19 | int[] c; // count for our picks 20 | 21 | public List validParentheses(int l, int m, int n) { 22 | List res = new ArrayList<>(); 23 | int len = 2 * (l + m + n); 24 | c = new int[]{l, l, m, m, n, n}; 25 | char[] cur = new char[len]; 26 | Deque stack = new ArrayDeque<>(); 27 | dfs(0, stack, cur, res); 28 | return res; 29 | } 30 | 31 | private void dfs(int idx, Deque stack, char[] cur, List res) { 32 | if (idx == cur.length) { 33 | res.add(new String(cur)); 34 | return; 35 | } 36 | 37 | for (int i = 0; i < c.length; i++) 38 | if (i % 2 == 0) { 39 | if (c[i] > 0) { 40 | stack.offerFirst(i); 41 | add(idx, i, cur); 42 | dfs(idx + 1, stack, cur, res); 43 | stack.pollFirst(); 44 | c[i]++; 45 | } 46 | } else { 47 | if (!stack.isEmpty() && stack.peekFirst() == i - 1) { 48 | stack.pollFirst(); 49 | add(idx, i, cur); 50 | dfs(idx + 1, stack, cur, res); 51 | stack.offerFirst(i-1); 52 | c[i]++; 53 | } 54 | } 55 | } 56 | 57 | private void add(int idx, int i, char[] cur) { 58 | c[i]--; 59 | cur[idx] = p[i]; 60 | } 61 | 62 | public static void main(String[] args) { 63 | AllValidPermutationsOfParenthesesII avpop2 = new AllValidPermutationsOfParenthesesII(); 64 | System.out.println(avpop2.validParentheses(2, 1, 1)); 65 | System.out.println(avpop2.validParentheses(3, 0, 0)); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /AllPermutationsOfSubsets.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given a string with no duplicate characters, return a list with all permutations of the string and all its subsets. 3 | 4 | Examples 5 | Set = “abc”, all permutations are [“”, “a”, “ab”, “abc”, “ac”, “acb”, “b”, “ba”, “bac”, “bc”, “bca”, “c”, “cb”, “cba”, “ca”, “cab”]. 6 | Set = “”, all permutations are [“”]. 7 | Set = null, all permutations are []. 8 | */ 9 | 10 | import java.util.ArrayList; 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | public class AllPermutationsOfSubsets { 16 | public List allPermutationsOfSubsets(String s) { // TC: e * n! * n, SC: n 17 | List res = new ArrayList<>(); 18 | if (s != null) dfs(0, s.toCharArray(), res); 19 | return res; 20 | } 21 | 22 | private void dfs(int idx, char[] A, List res) { 23 | res.add(new String(A, 0, idx)); 24 | 25 | for (int i = idx; i < A.length; i++) { 26 | if (i != idx) swap(A, i, idx); 27 | dfs(idx + 1, A, res); 28 | if (i != idx) swap(A, i, idx); 29 | } 30 | } 31 | 32 | private void swap(char[] A, int l, int r) { 33 | char ch = A[l]; 34 | A[l] = A[r]; 35 | A[r] = ch; 36 | } 37 | 38 | public static void main(String[] args) { 39 | AllPermutationsOfSubsets aps = new AllPermutationsOfSubsets(); 40 | List l1 = aps.allPermutationsOfSubsets("slu"); 41 | System.out.println(l1); // [, s, sl, slu, su, sul, l, ls, lsu, lu, lus, u, ul, uls, us, usl] 42 | System.out.println(l1.size()); // 16 43 | List l2 = aps.allPermutationsOfSubsets("fast"); 44 | System.out.println(l2); // [, f, fa, fas, fast, fat, fats, fs, fsa, fsat, fst, fsta, ft, fts, ftsa, fta, ftas, a, af, afs, afst, aft, afts, as, asf, asft, ast, astf, at, ats, atsf, atf, atfs, s, sa, saf, saft, sat, satf, sf, sfa, sfat, sft, sfta, st, stf, stfa, sta, staf, t, ta, tas, tasf, taf, tafs, ts, tsa, tsaf, tsf, tsfa, tf, tfs, tfsa, tfa, tfas] 45 | System.out.println(l2.size()); // 65 46 | l2 = l2.subList(0, 8); 47 | System.out.println(l2.size()); 48 | System.out.println(l2); 49 | l2.subList(8, l2.size()).clear(); 50 | System.out.println(l2); 51 | int target = 100, factor = 10; 52 | System.out.println(target /= factor); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /Tree/LongestAscendingPathBinaryTree.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | /* 3 | Determine the length of the longest ascending path in the binary tree. 4 | A valid path is a part of the path from root to any of the leaf nodes. 5 | 6 | Examples: 7 | 5 8 | / \ 9 | 3 2 10 | / \ \ 11 | 1 0 11 12 | 13 | the longest ascending path is 2 -> 11, length is 2. 14 | */ 15 | 16 | 17 | import util.TreeNode; 18 | 19 | public class LongestAscendingPathBinaryTree { 20 | static class Helper { 21 | int max = 0; 22 | } 23 | public int longest(TreeNode root) { 24 | Helper H = new Helper(); 25 | helper(root, null, 0, H); 26 | return H.max; 27 | } 28 | 29 | private void helper (TreeNode root, TreeNode pre, int cur, Helper H) { 30 | if (root == null) return; 31 | 32 | cur = pre != null && pre.key < root.key ? cur + 1 : 1; 33 | if (cur > H.max) H.max = cur; 34 | 35 | helper(root.left, root, cur, H); 36 | helper(root.right, root, cur, H); 37 | } 38 | 39 | public static void main(String[] args) { 40 | LongestAscendingPathBinaryTree lap = new LongestAscendingPathBinaryTree(); 41 | Integer[] arr = new Integer[]{487,132,214,344,185,null,404,428,246,403,146,223,47,250,132,337,166,152,429,5,280,425,148,283,388,61,205,401,null,111,414,163,478,483,null,358,420,165,130,391,null,263,null,324,445,460,66,323,450,214,158,253,255,270,403,17,323,437,248,417,274,134,41,496,226,406}; 42 | TreeNode root = TreeNode.fromLevelOrder(arr); 43 | // BTreePrinter.printNode(root); 44 | System.out.println(lap.longest(root)); // 4 45 | Integer[] a2 = new Integer[]{5, 3, 2, 1, 0, null, 11}; 46 | TreeNode r2 = TreeNode.fromLevelOrder(a2); 47 | // BTreePrinter.printNode(r2); 48 | System.out.println(lap.longest(r2)); // 2 49 | System.out.println(lap.longest(TreeNode.fromLevelOrder(new Integer[]{1}))); // 1 50 | System.out.println(lap.longest(TreeNode.fromLevelOrder(new Integer[]{1, 2}))); // 2 51 | System.out.println(lap.longest(TreeNode.fromLevelOrder(new Integer[]{1, 2, 3}))); // 2 52 | System.out.println(lap.longest(TreeNode.fromLevelOrder(new Integer[]{1, 2, 3, 4}))); // 3 53 | System.out.println(lap.longest(TreeNode.fromLevelOrder(new Integer[]{2, 1, 3}))); // 2 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Solutions/String and Array/32. Longest Valid Parentheses.md: -------------------------------------------------------------------------------- 1 | # [32. Longest Valid Parentheses](https://leetcode.com/problems/longest-valid-parentheses/) 2 | 3 | ## stack 4 | TC: O(n), SC: O(n) 5 | ### 思路 6 | 0. 定义一段valid括号的边界: (left, right], 左边不包含右边包含, right - left 正好是length, 这么做主要是为了方便 7 | 1. 初始化第一个valid括号的左边接(if exist)为-1 8 | 2. 每碰到一个左括号, push index进stack 9 | 3. 没碰到一个右括号,把自己对应的左括号先poll出来,这时候如果 10 | 1. stack为空,说明这个右括号是多余的(我们初始化时候多放了一个右括号) 11 | 1. push这个右括号的index进stack,作为之后valid 括号组合的valid 起点(exclusive) 12 | 2. stack不空, 现在是一组valid 括号string, stack里面的第一个index就是exclusive左边界,更新最大值 13 | ```java 14 | class Solution { 15 | public int longestValidParentheses(String str) { 16 | int n = str.length(), top = -1, res = 0; 17 | int[] s = new int[n + 1]; 18 | s[++top] = -1; 19 | 20 | for (int i = 0; i < n; i++) 21 | if (str.charAt(i) == '(') s[++top] = i; 22 | else if (--top < 0) s[++top] = i; 23 | else res = Math.max(res, i - s[top]); 24 | 25 | return res; 26 | } 27 | } 28 | ``` 29 | 30 | ## counter, space O(1) 31 | TC: O(n), SC: O(1) 32 | 33 | ### 思路 34 | 1. 从左往右数 35 | 1. '(' counter++, ')' counter-- 36 | 2. 同时记住length++; 37 | 3. 任何时候 counter < 0 都说明右括号多了 38 | 1. reset counter to 0 39 | 2. reset len = 0; 40 | 4. 任何时候counter == 0 说明是一个valid组合, 用length 去更新global max 41 | 2. 上面做法只能检测出右括号多的情况,但是如果左括号多了,会导致无法更新global max比如: 42 | 1. (()()()()(), 这个max应该是10,但是因为最前面多了个左括号,counter 永远不等于0,所以结果是0 43 | 3. 从右往左 44 | 1. 为了应对#2的问题,我们反着再来一次把左括号的问题处理掉 45 | ```java 46 | class Solution { 47 | public int longestValidParentheses(String s) { 48 | int cnt = 0, n = s.length(), len = 0, res = 0; 49 | 50 | for (int i = 0; i < n; i++) { 51 | if (s.charAt(i) == '(') cnt++; 52 | else cnt--; 53 | len++; 54 | if (cnt < 0) { 55 | cnt = 0; 56 | len = 0; 57 | } else if (cnt == 0) res = Math.max(res, len); 58 | } 59 | 60 | cnt = 0; len = 0; 61 | for (int i = n - 1; i >= 0; i--) { 62 | if (s.charAt(i) == ')') cnt++; 63 | else cnt--; 64 | len++; 65 | if (cnt < 0) { 66 | cnt = 0; 67 | len = 0; 68 | } else if (cnt == 0) res = Math.max(res, len); 69 | } 70 | 71 | return res; 72 | } 73 | } 74 | ``` -------------------------------------------------------------------------------- /Solutions/Tree/588. Design In-Memory File System.md: -------------------------------------------------------------------------------- 1 | # [588. Design In-Memory File System](https://leetcode.com/problems/design-in-memory-file-system/) 2 | 3 | ## quick and dirty but tasks completed, 38ms, 94.98% 4 | ```java 5 | private class File { 6 | Map files = new HashMap<>(); 7 | boolean isFile = false; 8 | StringBuilder content = new StringBuilder(); 9 | } 10 | 11 | class FileSystem { 12 | File root = new File(); 13 | 14 | public List ls(String path) { 15 | String[] a = path.split("/"); 16 | File cur = root; 17 | for (int i = 1; i < a.length; i++) 18 | cur = cur.files.get(a[i]); 19 | 20 | List res = new ArrayList<>(); 21 | if (!cur.isFile) { 22 | for (String s : cur.files.keySet()) res.add(s); 23 | Collections.sort(res); 24 | } else res.add(a[a.length-1]); 25 | 26 | return res; 27 | } 28 | 29 | public void mkdir(String path) { 30 | String[] a = path.split("/"); 31 | File cur = root; 32 | for (int i = 1; i < a.length; i++) { 33 | File next = cur.files.get(a[i]); 34 | if (next == null) cur.files.put(a[i], next = new File()); 35 | cur = next; 36 | } 37 | } 38 | 39 | public void addContentToFile(String path, String content) { 40 | String[] a = path.split("/"); 41 | File cur = root; 42 | for (int i = 1; i < a.length; i++) { 43 | File next = cur.files.get(a[i]); 44 | if (next == null) cur.files.put(a[i], next = new File()); 45 | cur = next; 46 | } 47 | cur.content.append(content); 48 | cur.isFile = true; 49 | } 50 | 51 | public String readContentFromFile(String path) { 52 | String[] a = path.split("/"); 53 | File cur = root; 54 | for (int i = 1; i < a.length; i++) { 55 | File next = cur.files.get(a[i]); 56 | if (next == null) cur.files.put(a[i], next = new File()); 57 | cur = next; 58 | } 59 | return cur.content.toString(); 60 | } 61 | } 62 | 63 | /** 64 | * Your FileSystem object will be instantiated and called as such: 65 | * FileSystem obj = new FileSystem(); 66 | * List param_1 = obj.ls(path); 67 | * obj.mkdir(path); 68 | * obj.addContentToFile(filePath,content); 69 | * String param_4 = obj.readContentFromFile(filePath); 70 | */ 71 | ``` 72 | -------------------------------------------------------------------------------- /Tree/SortedListToBinarySearchTree.java: -------------------------------------------------------------------------------- 1 | package Tree; 2 | 3 | import util.ListNode; 4 | import util.TreeNode; 5 | 6 | import java.util.List; 7 | 8 | import static util.Utils.listEqualsArray; 9 | 10 | /* 11 | Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST. 12 | For testing purpose, please make sure for any node in the result, its left subtree should have equal or only one more node than its right subtree. 13 | Example: 14 | Given ascending order list: 1→3→4→5→8→11 15 | return Binary Search Tree is 16 | 5 17 | / \ 18 | 3 11 19 | / \ / 20 | 1 4 8 21 | */ 22 | public class SortedListToBinarySearchTree { 23 | private int getSize(ListNode head) { 24 | int size = 0; 25 | for (; head != null; head = head.next) size++; 26 | return size; 27 | } 28 | 29 | private TreeNode BST(ListNode[] a, int l, int r) { 30 | if (l > r) return null; 31 | int mid = r - (r - l) / 2; 32 | TreeNode root = new TreeNode(a[mid].value); 33 | root.left = BST(a, l, mid - 1); 34 | root.right = BST(a, mid + 1, r); 35 | return root; 36 | } 37 | 38 | public TreeNode sortedListToBST(ListNode head) { 39 | int size = getSize(head); 40 | if (size == 0) return null; 41 | ListNode[] a = new ListNode[size]; 42 | for (int i = 0; i < size; i++) { 43 | a[i] = head; 44 | head = head.next; 45 | } 46 | return BST(a, 0, size - 1); 47 | } 48 | 49 | public static void main(String[] args) { 50 | SortedListToBinarySearchTree sol = new SortedListToBinarySearchTree(); 51 | int[] a = new int[]{16, 36, 39, 42, 76, 82, 86, 107, 117, 149, 153, 186, 188, 193, 204, 217, 237, 246, 248, 250, 255, 256, 257, 258, 259, 280, 300, 320, 321, 341, 350, 354, 364, 367, 371, 376, 385, 410, 413, 465, 474, 506, 511, 536, 549, 564, 568, 590, 605, 609, 620, 630, 639, 658, 668, 678, 683, 685, 700, 702, 714, 733, 752, 762, 779, 786, 810, 811, 812, 822, 825, 847, 854, 869, 874, 886, 896, 928, 930, 943, 945, 958, 963, 990, 992, 993}; 52 | ListNode head = ListNode.fromArray(a); 53 | TreeNode root = sol.sortedListToBST(head); 54 | List res = root.inOrder(); 55 | System.out.println(listEqualsArray(res, a)); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /Solutions/Misc/2402. Meeting Rooms III.md: -------------------------------------------------------------------------------- 1 | # [2402. Meeting Rooms III](https://leetcode.com/problems/meeting-rooms-iii/) 2 | ## two pqs, 90ms, 92.95% 3 | ```java 4 | class Solution { 5 | public int mostBooked(int n, int[][] meetings) { 6 | int[] cnt = new int[n]; 7 | Arrays.sort(meetings, (a, b) -> a[0] - b[0]); 8 | 9 | Queue q1 = new PriorityQueue<>((a, b) -> a[1] == b[1] ? Long.compare(a[0], b[0]) : Long.compare(a[1], b[1])); // a[0] room ID, a[i]: cur end time 10 | Queue q2 = new PriorityQueue<>((a, b) -> Long.compare(a[0], b[0])); // a[0] room ID 11 | for (int i = 0; i < n; i++) q1.offer(new long[]{i, 0}); 12 | 13 | for (var m : meetings) { 14 | while (!q1.isEmpty() && q1.peek()[1] <= m[0]) q2.offer(q1.poll()); 15 | long[] cur = q2.isEmpty() ? q1.poll() : q2.poll(); 16 | cnt[(int)(cur[0])]++; 17 | cur[1] = Math.max(cur[1] + m[1] - m[0], m[1]); 18 | q1.offer(cur); 19 | } 20 | 21 | int max = cnt[0], res = 0; 22 | for (int i = 1; i < n; i++) { 23 | if (cnt[i] > max) { 24 | max = cnt[i]; 25 | res = i; 26 | } 27 | } 28 | 29 | return res; 30 | } 31 | } 32 | 33 | /* 34 | // for (var a : meetings) 35 | // System.out.printf("%s, ", Arrays.toString(a)); 36 | // System.out.println(); 37 | 38 | // List[] mts = new List[n]; 39 | // for (int i = 0; i < n; i++) mts[i] = new ArrayList<>(); 40 | 41 | // System.out.printf("\nq1.peek(): %s\n", Arrays.toString(q1.peek())); 42 | 43 | // mts[cur[0]].add(m); 44 | 45 | // System.out.printf("\nq1.peek(): %s\n", Arrays.toString(q1.peek())); 46 | 47 | // int id = 0; 48 | // for (var l : mts) { 49 | // System.out.printf("%d(%d): ", id, cnt[id++]); 50 | // for (var a : l) System.out.printf("%s, ", Arrays.toString(a)); 51 | // System.out.println(); 52 | // } 53 | 54 | // System.out.println(Arrays.toString(cnt)); 55 | 56 | 2 57 | [[0,10],[1,5],[2,7],[3,4]] 58 | 2 59 | [[0,10],[1,5],[2,7],[3,4],[8,11],[9,12]] 60 | 3 61 | [[1,20],[2,10],[3,5],[4,9],[6,8]] 62 | 3 63 | [[3,7],[12,19],[16,17],[1,17],[5,6]] 64 | 4 65 | [[19,20],[14,15],[13,14],[11,20]] 66 | 4 67 | [[18,19],[3,12],[17,19],[2,13],[7,10]] 68 | */ 69 | ``` -------------------------------------------------------------------------------- /QuickSortLinkedList.java: -------------------------------------------------------------------------------- 1 | import util.ListNode; 2 | 3 | public class QuickSortLinkedList { 4 | private ListNode tail; 5 | public ListNode quickSort(ListNode head) { // TC: average O(nlogn), worst O(n^2), SC: O(log(n)) 6 | if (head == null) return null; 7 | if (head.next == null) return tail = head; 8 | 9 | ListNode small = new ListNode(0); // will use small as dummy head of all result 10 | ListNode large = new ListNode(0); 11 | partition(head, small, large); // use head as pivot 12 | head.next = null; // must cut it 13 | 14 | if (small.next != null) { 15 | small.next = quickSort(small.next); 16 | tail.next = head; 17 | } else small.next = head; 18 | tail = head; 19 | tail.next = quickSort(large.next); 20 | return small.next; 21 | } 22 | 23 | private void partition(ListNode head, ListNode small, ListNode large) { // Notice small & large, java pass by value 24 | ListNode cur = head.next; 25 | while (cur != null) { 26 | if (cur.value < head.value) { 27 | small.next = cur; 28 | small = small.next; 29 | } else { 30 | large.next = cur; 31 | large = large.next; 32 | } 33 | cur = cur.next; 34 | } 35 | small.next = large.next = null; 36 | } 37 | 38 | public static void main(String[] args) { 39 | QuickSortLinkedList qs = new QuickSortLinkedList(); 40 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{9, 7, 0, 5, 4, 1, 8, 2, 6, 3}))); 41 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{5, 4, 1, 2, 6, 3}))); 42 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{4, 2, 6, 3, 5}))); 43 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{8, 5, 3, 1}))); 44 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{1, -1, 0}))); 45 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{8, 5, 3}))); 46 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{2, 8}))); 47 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{8, 2}))); 48 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{3}))); 49 | System.out.println(qs.quickSort(ListNode.fromArray(new int[]{0}))); 50 | System.out.println(qs.quickSort(ListNode.fromArray(null))); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /RotateMatrix.java: -------------------------------------------------------------------------------- 1 | /* 2 | Rotate an N * N matrix clockwise 90 degrees. 3 | Assumptions 4 | The matrix is not null and N >= 0 5 | Examples 6 | { {1, 2, 3} 7 | {8, 9, 4}, 8 | {7, 6, 5} } 9 | 10 | after rotation is 11 | { {7, 8, 1} 12 | {6, 9, 2}, 13 | {5, 4, 3} } 14 | */ 15 | 16 | import java.util.Arrays; 17 | 18 | public class RotateMatrix { 19 | public void rotate(int[][] mx) { // TC:O(n^2), SC: O(1) 20 | for (int start = 0, end = mx.length - 1; start < end; start++, end--) 21 | for (int j = 0; j < end - start; j++) { // j: 0 ~ n - 2 on level 1 22 | int tmp = mx[start][start + j]; 23 | mx[start][start + j] = mx[end - j][start]; 24 | mx[end - j][start] = mx[end][end - j]; 25 | mx[end][end - j] = mx[start + j][end]; 26 | mx[start + j][end] = tmp; 27 | } 28 | } 29 | 30 | public static boolean mxEqual(int[][] A, int [][] B) { 31 | if (A.length != B.length) return false; 32 | if (A[0].length != B[0].length) return false; 33 | for (int i = 0; i < A.length; i++) { 34 | if (!Arrays.equals(A[i], B[i])) return false; 35 | } 36 | return true; 37 | } 38 | 39 | public static void printMX(int[][] mx) { 40 | System.out.println(); 41 | for (int[] row : mx) 42 | System.out.println(Arrays.toString(row)); 43 | } 44 | 45 | public static void main(String[] args) { 46 | int[][] mx = new int[][]{{67,16,45,46,68,5,41,28},{29,68,56,45,87,98,84,72},{57,98,18,55,10,56,37,46},{96,4,51,39,55,32,44,73},{73,42,71,22,90,98,7,66},{51,85,79,91,3,40,33,61},{37,6,20,74,77,25,83,8},{75,28,37,63,54,53,24,67}}; 47 | int[][] expected = new int[][]{{75, 37, 51, 73, 96, 57, 29, 67}, {28, 6, 85, 42, 4, 98, 68, 16}, {37, 20, 79, 71, 51, 18, 56, 45}, {63, 74, 91, 22, 39, 55, 45, 46}, {54, 77, 3, 90, 55, 10, 87, 68}, {53, 25, 40, 98, 32, 56, 98, 5}, {24, 83, 33, 7, 44, 37, 84, 41}, {67, 8, 61, 66, 73, 46, 72, 28}}; 48 | 49 | printMX(mx); 50 | printMX(expected); 51 | RotateMatrix rm = new RotateMatrix(); 52 | rm.rotate(mx); 53 | printMX(mx); 54 | System.out.println(mxEqual(expected, mx)); 55 | 56 | // simpler demo 57 | int[][] mx2 = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; 58 | printMX(mx2); 59 | rm.rotate(mx2); 60 | printMX(mx2); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AllAnagrams.java: -------------------------------------------------------------------------------- 1 | //Find all occurrence of anagrams of a given string s in a given string l. Return the list of starting indices. 2 | // 3 | // Assumptions 4 | // 5 | // s is not null or empty. 6 | // s is not null. 7 | // Examples 8 | // 9 | // l = "abcbac", s = "ab", return [0, 3] since the substring with length 2 starting from index 0/3 are all anagrams of "ab" ("ab", "ba"). 10 | 11 | import java.util.*; 12 | 13 | public class AllAnagrams { 14 | public static List allAnagrams(String s, String l) { 15 | List res = new ArrayList<>(); 16 | 17 | Map map = new HashMap<>(); 18 | for (int i = 0; i < s.length(); i++) 19 | map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1); 20 | 21 | int toMatch = map.size(); 22 | for (int j = 0; j < l.length(); j++) { 23 | toMatch = updateMap(-1, l.charAt(j), toMatch, map); 24 | if (j >= s.length()) 25 | toMatch = updateMap(1, l.charAt(j - s.length()), toMatch, map); 26 | if (toMatch == 0) res.add(j - s.length() + 1); // j - s.length() is what we just got rid of, so next index is the start of the keeper substring 27 | } 28 | 29 | return res; 30 | } 31 | 32 | private static int updateMap(int val, char ch, int toMatch, Map map) { 33 | Integer count = map.get(ch); 34 | if (count == null) return toMatch; 35 | if (count == 0) toMatch++; // count changed from 0 to not 0(1/-1), we lost the match of one char, so toMatch++ 36 | map.put(ch, count += val); 37 | if (count == 0) toMatch--; // count changed from not 0(1/-1) to 0, we matched one more char, so toMatch-- 38 | return toMatch; 39 | } // TC: O(m + n), SC: O(m), m is the length of s and n is the length of l 40 | 41 | private static List toList(int[] A) { 42 | List res = new ArrayList<>(A.length); 43 | for (int i : A) res.add(i); 44 | return res; 45 | } 46 | 47 | public static void main(String[] args) { 48 | List res1 = allAnagrams("ab", "abcbac"); 49 | System.out.println(res1); 50 | System.out.println("Is above result correct ? " + res1.equals(toList(new int[]{0, 3}))); 51 | List res2 = allAnagrams("aab", "ababacbbaac"); 52 | System.out.println(res2); 53 | System.out.println("Is above result correct ? " + res2.equals(toList(new int[]{0, 2, 7}))); 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /AllValidPermutationsOfParenthesesIII.java: -------------------------------------------------------------------------------- 1 | /* 2 | Get all valid permutations of l pairs of (), m pairs of <> and n pairs of {}, 3 | subject to the priority restriction: {} higher than <> higher than (). 4 | 5 | Assumptions 6 | 7 | l, m, n >= 0 8 | l + m + n >= 0 9 | 10 | Examples 11 | 12 | l = 1, m = 1, n = 0, all the valid permutations are ["()<>", "<()>", "<>()"]. 13 | l = 2, m = 0, n = 1, all the valid permutations are [“()(){}”, “(){()}”, “(){}()”, “{()()}”, “{()}()”, “{}()()”]. 14 | */ 15 | 16 | 17 | import java.util.ArrayDeque; 18 | import java.util.ArrayList; 19 | import java.util.Deque; 20 | import java.util.List; 21 | 22 | public class AllValidPermutationsOfParenthesesIII { 23 | char[] p = new char[] {'(', ')', '<', '>', '{', '}'}; // pick array 24 | int[] c; // count for our picks 25 | 26 | public List validParenthesesIII(int l, int m, int n) { 27 | List res = new ArrayList<>(); 28 | int len = 2 * (l + m + n); 29 | c = new int[]{l, l, m, m, n, n}; 30 | char[] cur = new char[len]; 31 | Deque stack = new ArrayDeque<>(); 32 | dfs(0, stack, cur, res); 33 | return res; 34 | } 35 | 36 | private void dfs(int idx, Deque stack, char[] cur, List res) { 37 | if (idx == cur.length) { 38 | res.add(new String(cur)); 39 | return; 40 | } 41 | 42 | for (int i = 0; i < c.length; i++) 43 | if (i % 2 == 0) { 44 | if (c[i] > 0 && (stack.isEmpty() || i <= stack.peekFirst())) { 45 | stack.offerFirst(i); 46 | add(idx, i, cur); 47 | dfs(idx + 1, stack, cur, res); 48 | stack.pollFirst(); 49 | c[i]++; 50 | } 51 | } else { 52 | if (!stack.isEmpty() && stack.peekFirst() == i - 1) { 53 | stack.pollFirst(); 54 | add(idx, i, cur); 55 | dfs(idx + 1, stack, cur, res); 56 | stack.offerFirst(i-1); 57 | c[i]++; 58 | } 59 | } 60 | } 61 | 62 | private void add(int idx, int i, char[] cur) { 63 | c[i]--; 64 | cur[idx] = p[i]; 65 | } 66 | 67 | public static void main(String[] args) { 68 | AllValidPermutationsOfParenthesesIII avpop3 = new AllValidPermutationsOfParenthesesIII(); 69 | System.out.println(avpop3.validParenthesesIII(3, 1, 0)); 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /RotateListbyKplaces.java: -------------------------------------------------------------------------------- 1 | import util.ListNode; 2 | 3 | public class RotateListbyKplaces { 4 | // sol 1 5 | public ListNode rotateKplace(ListNode head, int k) { // TC: O(n + n - k), SC: O(1) 6 | if (head == null) return null; 7 | ListNode cur = head; 8 | int len = 1; 9 | while (cur.next != null) { 10 | cur = cur.next; 11 | len++; 12 | } 13 | 14 | cur.next = head; 15 | 16 | for (int i = 0; i < len - (k %= len); i++) cur = cur.next; 17 | 18 | head = cur.next; 19 | cur.next = null; 20 | return head; 21 | } 22 | // sol1 ends here 23 | 24 | // sol 2 slightly optimized 25 | // When k > n, TC for this solution is same as solution 1 26 | // when k < n,TC: k + 2 * (n - k) (cause we're moving 2 pointers) 2n - k, it's the same... 27 | // SC: O(1) 28 | public ListNode rotateKplace2(ListNode head, int k) { 29 | if (head == null) return null; 30 | 31 | ListNode cur = head; 32 | int len = 1; 33 | for (int i = 0; i < k && cur.next != null; i++) { 34 | cur = cur.next; 35 | len++; 36 | } 37 | 38 | // this means k is not longer than length of list, then we can return faster using two pointers 39 | if (cur.next != null) return faster(head, cur); 40 | 41 | cur.next = head; 42 | 43 | for (int i = 0; i < len - (k %= len); i++) cur = cur.next; 44 | 45 | head = cur.next; 46 | cur.next = null; 47 | return head; 48 | } 49 | 50 | private ListNode faster(ListNode head, ListNode fast) { 51 | ListNode slow = head; 52 | while (fast.next != null) { 53 | slow = slow.next; 54 | fast = fast.next; 55 | } 56 | fast.next = head; 57 | head = slow.next; 58 | slow.next = null; 59 | return head; 60 | } 61 | // sol 2 ends here 62 | 63 | public static void main(String[] args) { 64 | ListNode root = ListNode.fromArray(new int[] {1, 2, 3, 4, 5}); 65 | RotateListbyKplaces sol = new RotateListbyKplaces(); 66 | System.out.println(root); 67 | System.out.println(root = sol.rotateKplace(root, 2)); 68 | System.out.println(root = sol.rotateKplace(root, 3)); 69 | 70 | System.out.println(); 71 | System.out.println(root = sol.rotateKplace(root, 2)); 72 | System.out.println(root = sol.rotateKplace(root, 3)); 73 | System.out.println(root = sol.rotateKplace(root, 13)); 74 | System.out.println(root = sol.rotateKplace(root, 12)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test/CompressTest.java: -------------------------------------------------------------------------------- 1 | import org.junit.jupiter.api.Test; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | 5 | class CompressTest { 6 | 7 | String tc1 = "aaaaaaaaaccccmmittttttttttbbbbbbbbbccccccc"; 8 | String tc2 = "aufdnqpmhkndmvaodknreakgpkpwxxilggi"; 9 | String tc3 = "abcddddddddddddddddddddabc"; 10 | String tc4 = "hhhhhhhhhhhhhhhhhhhhhxxxxxxxxxxxxxxaaaaaaaaaddddffffooooooooooooll"; 11 | String tc5 = "abcddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddabc"; 12 | String decomp1 = "a13b21c0d2e11f13"; 13 | String decompRes1 = "aaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbddeeeeeeeeeeefffffffffffff"; 14 | String decomp2 = "a0"; 15 | String decompRes2 = ""; 16 | String decomp3 = "a5b0c0d0e0"; 17 | String decompRes3 = "aaaaa"; 18 | String decomp4 = "a15b0c0d0e15"; 19 | String decompRes4 = "aaaaaaaaaaaaaaaeeeeeeeeeeeeeee"; 20 | String decomp5 = "a2b2c2e2"; 21 | String decompRes5 = "aabbccee"; 22 | String decomp6 = "a0b21c2d3e4"; 23 | String decompRes6 = "bbbbbbbbbbbbbbbbbbbbbccdddeeee"; 24 | String decomp7 = "e4d3c2b21a0"; 25 | String decompRes7 = "eeeedddccbbbbbbbbbbbbbbbbbbbbb"; 26 | String decomp8 = "ap2lec3n"; 27 | String decompRes8 = "applecccn"; 28 | 29 | @Test 30 | void tc1() {assertEquals(tc1, Decompress.decompress(Compress.compress(tc1, true)));} 31 | @Test 32 | void tc2() {assertEquals(tc2, Decompress.decompress(Compress.compress(tc2, true)));} 33 | @Test 34 | void tc3() {assertEquals(tc3, Decompress.decompress(Compress.compress(tc3, true)));} 35 | @Test 36 | void tc4() {assertEquals(tc4, Decompress.decompress(Compress.compress(tc4, true)));} 37 | @Test 38 | void tc5() {assertEquals(tc5, Decompress.decompress(Compress.compress(tc5, true)));} 39 | @Test 40 | void decomp1() {assertEquals(decompRes1, Decompress.decompress(decomp1));} 41 | @Test 42 | void decomp2() {assertEquals(decompRes2, Decompress.decompress(decomp2));} 43 | @Test 44 | void decomp3() {assertEquals(decompRes3, Decompress.decompress(decomp3));} 45 | @Test 46 | void decomp4() {assertEquals(decompRes4, Decompress.decompress(decomp4));} 47 | @Test 48 | void decomp5() {assertEquals(decompRes5, Decompress.decompress(decomp5));} 49 | @Test 50 | void decomp6() {assertEquals(decompRes6, Decompress.decompress(decomp6));} 51 | @Test 52 | void decomp7() {assertEquals(decompRes7, Decompress.decompress(decomp7));} 53 | @Test 54 | void decomp8() {assertEquals(decompRes8, Decompress.decompress(decomp8, false));} 55 | } 56 | -------------------------------------------------------------------------------- /SelectionSortLinkedList.java: -------------------------------------------------------------------------------- 1 | import util.ListNode; 2 | 3 | public class SelectionSortLinkedList { 4 | // Solution 1 5 | public static ListNode selectionSort(ListNode head) { // Lai28, TCO(n^2), SC: O(1) 6 | if (head == null || head.next == null) return head; 7 | // ListNode dummy = new ListNode(0, head); 8 | ListNode dummy = new ListNode(0); 9 | dummy.next = head; 10 | ListNode sorted = new ListNode(0); 11 | ListNode cur = sorted; // cur is the iteration node of result LinkedList 12 | while (dummy.next != null) { // every iteration we delete one node from dummy, insert one to sorted 13 | ListNode minPre = dummy; // default first Node as min / minPre 14 | for (head = minPre.next; head.next != null; head = head.next) // find pre Node for min in current LinkedList 15 | if (head.next.value < minPre.next.value) minPre = head; 16 | cur.next = minPre.next; // insert min to new LinkedList 17 | cur = cur.next; // maintain cur as last node of sorted to take in new value 18 | minPre.next = minPre.next.next; // delete min from original LinkedList 19 | } 20 | 21 | return sorted.next; 22 | } 23 | // Solution 1 ends here 24 | 25 | // Solution 2 "in-place"? TC: O(n^2), SC: O(1) 26 | public static ListNode selectionSort2(ListNode head) { // Lai28 27 | if (head == null || head.next == null) return head; 28 | ListNode dummy = new ListNode(0); 29 | dummy.next = head; 30 | 31 | for (ListNode slow = dummy; slow.next != null; slow = slow.next, head = slow.next) { 32 | ListNode minPre = slow; 33 | for (;head.next != null; head = head.next) 34 | if (head.next.value < minPre.next.value) minPre = head; 35 | 36 | if (minPre.next == slow.next) continue; 37 | ListNode min = removeNext(minPre); 38 | insertNodeNext(slow, min); 39 | } 40 | return dummy.next; 41 | } 42 | 43 | private static void insertNodeNext(ListNode head, ListNode node) { 44 | node.next = head.next; 45 | head.next = node; 46 | } 47 | 48 | private static ListNode removeNext(ListNode head) { 49 | ListNode min = head.next; 50 | head.next = min.next; 51 | min.next = null; 52 | return min; 53 | } 54 | // Solution 2 ends here 55 | 56 | public static void main(String[] args) { 57 | ListNode ll = ListNode.fromArray(new int[]{5, 4, 1, 2, 6, 3}); 58 | ll = selectionSort2(ll);System.out.println(ll); 59 | ll = selectionSort(ll);System.out.println(ll); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Solutions/DP/416. Partition Equal Subset Sum.md: -------------------------------------------------------------------------------- 1 | # [416. Partition Equal Subset Sum](https://leetcode.com/problems/partition-equal-subset-sum/description/) 2 | 3 | ## 2d, DP, 55ms 64.68% 4 | ```java 5 | class Solution { 6 | public boolean canPartition(int[] a) { 7 | int sum = Arrays.stream(a).sum(); 8 | if (sum % 2 != 0) return false; 9 | int target = sum / 2, n = a.length; 10 | 11 | // dp[i][j] use up to i nums where i:[0, n], to get to target of j where j:[0,sum] 12 | boolean[][] dp = new boolean[n+1][target+1]; 13 | // dp[i][0]: use first i elements to sum to 0, if we chose not to use any i, it's true to get to 0 14 | for (int i = 0; i <= n; i++) dp[i][0] = true; 15 | 16 | for (int i = 1; i <= n; i++) { // try each element 17 | for (int j = a[0]; j <= target; j++) { 18 | dp[i][j] = dp[i-1][j]; // do not use current number 19 | if (!dp[i][j] && j - a[i-1] >= 0) dp[i][j] |= dp[i-1][j-a[i-1]]; // use current number 20 | } 21 | } 22 | 23 | return dp[n][target]; 24 | } 25 | } 26 | ``` 27 | 28 | ## 1D, dp, 27ms, 91.92% 29 | ```java 30 | class Solution { 31 | public boolean canPartition(int[] a) { 32 | int sum = Arrays.stream(a).sum(); 33 | if (sum % 2 != 0) return false; 34 | int target = sum / 2, n = a.length; 35 | 36 | boolean[] dp = new boolean[target+1]; 37 | // dp[j]: use first 0 element to sum to j 38 | dp[0] = true; 39 | 40 | for (int x : a) { // try each element 41 | for (int j = target; j >= x; j--) { 42 | dp[j] |= dp[j-x]; // use current number 43 | } 44 | } 45 | return dp[target]; 46 | } 47 | } 48 | ``` 49 | 50 | ## recursion + MEMO, 29ms, 89.59% 51 | ```java 52 | class Solution { 53 | public boolean canPartition(int[] a) { 54 | int sum = Arrays.stream(a).sum(); 55 | if (sum % 2 != 0) return false; 56 | int target = sum / 2, n = a.length; 57 | Boolean[][] dp =new Boolean[n][target+1]; 58 | dfs(0, target, a, dp); 59 | // System.out.println(Arrays.toString(dp)); 60 | return dp[0][target]; // starting from 0, can be met target 61 | } 62 | 63 | private boolean dfs(int i, int t, int[] a, Boolean[][] dp) { 64 | if (t == 0) return true; 65 | if (t < 0 || i == a.length) return false; 66 | if (dp[i][t] != null) return dp[i][t]; 67 | 68 | dp[i][t] = dfs(i+1, t-a[i], a, dp) || dfs(i+1, t, a, dp); 69 | 70 | return dp[i][t]; 71 | } 72 | } 73 | ``` -------------------------------------------------------------------------------- /SearchInSortedMatrixII.java: -------------------------------------------------------------------------------- 1 | import java.util.Arrays; 2 | 3 | /* 4 | Given a 2D matrix that contains integers only, 5 | which each row is sorted in ascending order and each column is also sorted in ascending order. 6 | Given a target number, returning the position that the target locates within the matrix. 7 | If the target number does not exist in the matrix, return {-1, -1}. 8 | Assumptions: 9 | The given matrix is not null. 10 | Examples: 11 | matrix = { {1, 2, 3}, {2, 4, 5}, {6, 8, 10} } 12 | target = 5, return {1, 2} 13 | target = 7, return {-1, -1} 14 | */ 15 | public class SearchInSortedMatrixII { 16 | /* 17 | Divide the matrix into max 4 smaller matrices (3 is enough actually), we can get rid of at least 1/4 each time. 18 | Use recursion to facilitate with handing corner cases. 19 | On average, we get rid of 1/4 each time, so the search space become 3/4 each time. 20 | Let total number of searches be x and total elements in matrix be n 21 | (1 - 1/4) ^ x * n = 1 ==> (3/4)^x = 1/n ==> (4/3)^x = n ==> x = log(4/3)_n; 22 | TC: log(4/3)_n (round of searches) 23 | SC: log(4/3)_n (height of recursion tree) 24 | */ 25 | public int[] search(int[][] mx, int t) { 26 | if (mx.length == 0 || mx[0].length == 0) return new int[] {-1, -1}; 27 | int rows = mx.length, cols = mx[0].length; 28 | int l = 0, r = rows * cols - 1; 29 | return search(mx, t, 0, 0, rows - 1, cols - 1); 30 | } 31 | 32 | private int[] search(int[][] mx, int t, int x1, int y1, int x2, int y2) { 33 | if (x1 > x2 || y1 > y2) return new int[] {-1, -1}; 34 | if (x1 == x2 && y1 == y2) return mx[x1][y1] == t ? new int[]{x1, y1} : new int[] {-1, -1}; 35 | if (t < mx[x1][y1] || t > mx[x2][y2]) return new int[] {-1, -1}; 36 | 37 | int x0 = x1 + (x2 - x1) / 2; 38 | int y0 = y1 + (y2 - y1) / 2; 39 | 40 | int[] res = search(mx, t, x1, y1, x0, y0); 41 | if (res[0] != -1)return res; 42 | res = search(mx, t, x1, y0 + 1, x2, y2); 43 | if (res[0] != -1)return res; 44 | res = search(mx, t, x0 + 1, y1, x2, y0); 45 | return res[0] != -1 ? res : new int[] {-1, -1}; 46 | } 47 | 48 | public static void main(String[] args) { 49 | SearchInSortedMatrixII sol = new SearchInSortedMatrixII(); 50 | int[] a = new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1}; 51 | System.out.println(Arrays.toString(sol.search(new int[][]{{1}, {2}, {3}, {4}}, 2))); // [1, 0] 52 | System.out.println(Arrays.toString(sol.search(new int[][]{{1, 2, 3, 4}, {2, 5, 8, 9}, {3, 7, 11, 11}}, 7))); // [2, 1] 53 | 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Solutions/DP/256. Paint House.md: -------------------------------------------------------------------------------- 1 | [256. Paint House](https://leetcode.com/problems/paint-house/) 2 | [265. Paint House II](https://leetcode.com/problems/paint-house-ii/) 3 | 4 | ## Same problem, same code 5 | ## 2d DP 6 | TC: O(n*k^2), SC: O(k^2), n: number of houses, k: number colors 7 | ```java 8 | class Solution { 9 | public int minCost(int[][] costs) { 10 | int num = costs.length; 11 | int col = costs[0].length; 12 | int[][] dp = new int[num][col]; 13 | dp[0] = costs[0]; 14 | 15 | for (int i = 1; i < num; i++) for (int j = 0; j < col; j++) for (int k = 0; k < col; k++) 16 | if (k != j) 17 | dp[i][j] = dp[i][j] == 0 ? dp[i - 1][k] + costs[i][j] : Math.min(dp[i][j], dp[i - 1][k] + costs[i][j]); 18 | 19 | int res = dp[num - 1][0]; 20 | for (int i = 1; i < col; i++) res = Math.min(res, dp[num - 1][i]); 21 | return res; 22 | } 23 | } 24 | ``` 25 | 26 | ## optimized: only need to remember 3 (6) variables 27 | TC: O(n*k), SC: O(1) 28 | ```java 29 | class Solution { 30 | public int minCost(int[][] costs) { 31 | int m = costs.length, n = costs[0].length; 32 | int preMin = 0, preMinIdx = -1, preMin2 = 0; 33 | for (int[] cost : costs) { 34 | int curMin = Integer.MAX_VALUE, curMinIdx = -1, curMin2 = Integer.MAX_VALUE; 35 | for (int j = 0; j < costs[0].length; j++) { 36 | int val = cost[j] + (j != preMinIdx ? preMin : preMin2); 37 | if (curMinIdx == -1) { 38 | curMinIdx = j; 39 | curMin = val; 40 | } else if (val < curMin) { 41 | curMin2 = curMin; 42 | curMin = val; 43 | curMinIdx = j; 44 | } else if (val < curMin2) curMin2 = val; 45 | } 46 | preMin = curMin; 47 | preMin2 = curMin2; 48 | preMinIdx = curMinIdx; 49 | } 50 | 51 | return preMin; 52 | } 53 | } 54 | ``` 55 | ## For 256 only 56 | not the best,but good optimization 57 | ```java 58 | class Solution { 59 | public int minCost(int[][] costs) { 60 | int n = costs.length; 61 | int[][] dp = new int[2][3]; 62 | dp[0] = costs[0]; // paint 1st house with each color 63 | 64 | for (int i = 1; i < n; i++) { 65 | int i0 = i%2, i1 = (i-1)%2; 66 | for (int j = 0; j < 3; j++) 67 | dp[i0][j] = Math.min(dp[i1][(j-1+3)%3], dp[i1][(j+1)%3]) + costs[i][j]; 68 | } 69 | 70 | int res = dp[(n-1)%2][0]; 71 | for (int x : dp[(n-1)%2]) if (x < res) res = x; 72 | return res; 73 | } 74 | } 75 | ``` -------------------------------------------------------------------------------- /Solutions/Misc/OAs.md: -------------------------------------------------------------------------------- 1 | # OAs 2 | 3 | ## 2 sigma 4 |
 5 | 5.. 下水道出水, Tree, 分成两个tree, 让出水量差最小
 6 | inputs:
 7 | parent: List(int): parent = j => j 是 i 的parent
 8 | inputs: List(int): 每个node的额外出水量
 9 | Example 1: 
10 | Parent ={-1,0,0,0}  input ={10,11,10,10}
11 | Return 19 , cut 1 for one substree, {0,2,3} for another, so best is 30 -11 = 19
12 | Example2:
13 | Parent ={-1, 0,0,1,1,2}  input= {1,2,2,1,1,1}
14 | (0,2,5} and {1,3,4}   so return 0;
15 | 
16 | 17 | ### TC/SC: O(n) 18 | ```java 19 | public class DebugSolution { 20 | public static void main(String[] args) { 21 | Solution sol = new Solution(); 22 | System.out.println("Case 1:"); 23 | System.out.printf("Result : %d\n\n", sol.minSplit(new int[]{-1, 0, 0, 1, 1, 2}, new int[]{1, 2, 2, 1, 1, 1})); 24 | System.out.println("Case 2:"); 25 | System.out.printf("Result : %d\n\n", sol.minSplit(new int[]{-1, 0, 1, 2}, new int[]{1, 4, 3, 4})); 26 | System.out.println("Case 3:"); 27 | System.out.printf("Result : %d\n\n", sol.minSplit(new int[]{-1, 0, 0, 0}, new int[]{10, 11, 10, 10})); 28 | } 29 | } 30 | 31 | class Solution { 32 | public int minSplit(int[] p, int[] a) { 33 | System.out.printf("Parent : %s\n", Arrays.toString(p)); 34 | System.out.printf("Input : %s\n", Arrays.toString(a)); 35 | int n = a.length, res = Integer.MAX_VALUE; 36 | // get sum for each subtree 37 | for (int i = n-1; i >= 1; i--) a[p[i]] += a[i]; 38 | System.out.printf("Sum'd : %s\n", Arrays.toString(a)); 39 | 40 | // find the min diff between subtree sum and rest of the tree; 41 | for (int i = 1; i < n; i++) res = Math.min(res, Math.abs(a[0] - 2*a[i])); // a[0] is the sum of whole tree 42 | 43 | return res; 44 | } 45 | } 46 | ``` 47 | ### without prints 48 | ```java 49 | class Solution { 50 | public int minSplit(int[] p, int[] a) { 51 | int n = a.length, res = Integer.MAX_VALUE; 52 | // get sum for each subtree 53 | for (int i = n-1; i >= 1; i--) a[p[i]] += a[i]; 54 | // find the min diff between subtree sum and rest of the tree; 55 | for (int i = 1; i < n; i++) res = Math.min(res, Math.abs(a[0] - 2*a[i])); // a[0] is the sum of whole tree 56 | 57 | return res; 58 | } 59 | } 60 | ``` 61 | ### sample result prints 62 |
63 | Case 1:
64 | Parent : [-1, 0, 0, 1, 1, 2]
65 | Input  : [1, 2, 2, 1, 1, 1]
66 | Sum'd  : [8, 4, 3, 1, 1, 1]
67 | Result : 0
68 | 
69 | Case 2:
70 | Parent : [-1, 0, 1, 2]
71 | Input  : [1, 4, 3, 4]
72 | Sum'd  : [12, 11, 7, 4]
73 | Result : 2
74 | 
75 | Case 3:
76 | Parent : [-1, 0, 0, 0]
77 | Input  : [10, 11, 10, 10]
78 | Sum'd  : [41, 11, 10, 10]
79 | Result : 19
80 | 
-------------------------------------------------------------------------------- /test/utilTest/HeapTest.java: -------------------------------------------------------------------------------- 1 | package utilTest; 2 | 3 | import static org.junit.jupiter.api.Assertions.*; 4 | import org.junit.jupiter.api.Test; 5 | import util.Heap; 6 | 7 | import java.util.Arrays; 8 | import java.util.Comparator; 9 | import java.util.PriorityQueue; 10 | 11 | 12 | class HeapTest { 13 | Integer[] A1 = new Integer[]{8 , 7, 4, 2, 9, 5, 3, 1, 0, 6}; 14 | Integer[] A2 = new Integer[]{7, 3, 11, 1, 5, 9, 13, 0, 2, 4, 6, 8, 10, 12, 14}; 15 | 16 | int[] pqToIntArray(PriorityQueue pq) { 17 | int[] res = new int[pq.size()]; 18 | for (int i = 0; i < res.length; i++) 19 | res[i] = pq.poll(); 20 | return res; 21 | } 22 | int[] pqToIntArray(Heap pq) { 23 | int[] res = new int[pq.size()]; 24 | for (int i = 0; i < res.length; i++) 25 | res[i] = pq.poll(); 26 | return res; 27 | } 28 | 29 | // @Test 30 | // void peek() {assertEquals(pq1.peek(), mh1.peek());} 31 | // @Test 32 | // void size() {assertEquals(pq1.size(), mh1.size());} 33 | 34 | @Test 35 | void poll() {assertArrayEquals(pqToIntArray(new PriorityQueue<>(Arrays.asList(A1))), pqToIntArray(new Heap(A1)));} 36 | 37 | @Test 38 | void poll2() {assertArrayEquals(pqToIntArray(new PriorityQueue<>(Arrays.asList(A2))), pqToIntArray(new Heap(A2)));} 39 | 40 | @Test 41 | void offer() { 42 | PriorityQueue pq2 = new PriorityQueue<>(Arrays.asList(A2)); 43 | Heap mh2 = new Heap(A2); 44 | pq2.poll();mh2.poll(); 45 | pq2.offer(-5);mh2.offer(-5); 46 | assertArrayEquals(pqToIntArray(pq2), pqToIntArray(mh2)); 47 | } 48 | 49 | @Test 50 | void update() { 51 | PriorityQueue pq2 = new PriorityQueue<>(Arrays.asList(A2)); 52 | Heap mh2 = new Heap(A2); 53 | mh2.poll();pq2.poll(); 54 | pq2.offer(-5);mh2.offer(-5); 55 | assertArrayEquals(pqToIntArray(pq2), pqToIntArray(mh2)); 56 | } 57 | 58 | @Test 59 | void HeapSort1() { 60 | Heap heap = new Heap(A1, Comparator.reverseOrder()); // need max heap for heap sort 61 | Integer[] A1b = Arrays.copyOf(A1, A1.length); 62 | Arrays.sort(A1b); 63 | heap.heapsort(); 64 | assertArrayEquals(A1b, heap.array()); 65 | } 66 | 67 | @Test 68 | void HeapSort2() { 69 | Heap heap = new Heap(A2, Comparator.reverseOrder());// need max heap for heap sort 70 | Integer[] A2b = Arrays.copyOf(A2, A2.length); 71 | Arrays.sort(A2b); 72 | heap.heapsort(); 73 | assertArrayEquals(A2b, heap.array()); 74 | } 75 | 76 | @Test 77 | void isEmpty() { 78 | } 79 | 80 | @Test 81 | void isFull() { 82 | } 83 | } -------------------------------------------------------------------------------- /util/Trie.java: -------------------------------------------------------------------------------- 1 | package util; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | class TrieNode { 7 | public Map children = new HashMap<>(); 8 | boolean isWord; 9 | int count; 10 | } 11 | 12 | public class Trie { 13 | private final TrieNode root; 14 | 15 | public Trie() { 16 | root = new TrieNode(); 17 | } 18 | 19 | public TrieNode getRoot() { 20 | return root; 21 | } 22 | 23 | public boolean insert(String s) { 24 | if (search(s)) return false; 25 | 26 | TrieNode cur = root; 27 | for (int i = 0; i < s.length(); i++) { 28 | char c = s.charAt(i); 29 | TrieNode next = cur.children.get(c); 30 | if (next == null) { 31 | next = new TrieNode(); 32 | cur.children.put(c, next); 33 | } 34 | next.count++; 35 | cur = next; 36 | } 37 | return cur.isWord = true; 38 | } 39 | 40 | public boolean delete(String s) { 41 | if (!search(s)) return false; 42 | TrieNode cur = root; 43 | for (int i = 0; i < s.length(); i++) { 44 | char c = s.charAt(i); 45 | TrieNode next = cur.children.get(c); 46 | next.count--; 47 | if (next.count == 0) { 48 | cur.children.remove(c); 49 | return true; 50 | } 51 | cur = next; 52 | } 53 | cur.isWord = false; 54 | return true; 55 | } 56 | 57 | public boolean search(String s) { 58 | TrieNode cur = root; 59 | for (int i = 0; i < s.length(); i++) { 60 | TrieNode next = cur.children.get(s.charAt(i)); 61 | if (next == null) return false; 62 | cur = next; 63 | } 64 | return cur.isWord; 65 | } 66 | } 67 | 68 | class DebugTrie { 69 | public static void main(String[] args) { 70 | Trie trie = new Trie(); 71 | for (String s : new String[]{"cat", "app", "apple", "apples", "dog", "doggy", "tesla"}) 72 | trie.insert(s); 73 | 74 | System.out.println(trie.search("app")); // true 75 | System.out.println(trie.search("apple")); // true 76 | 77 | System.out.println(trie.delete("apple")); // true 78 | System.out.println(trie.search("apple")); // false 79 | System.out.println(trie.insert("apple")); // true 80 | System.out.println(trie.insert("apple")); // false 81 | System.out.println(trie.search("apple")); // true 82 | trie.delete("app"); 83 | System.out.println(trie.search("apple")); // true 84 | System.out.println(trie.search("app")); // false 85 | } 86 | } -------------------------------------------------------------------------------- /RestoreIPAddresses.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given a string containing only digits, restore it by retiring all possible valid IP address combinations. 3 | 4 | Input: ”25525511135” 5 | Output: [“255.255.11.135”, “255.255.111.35”] 6 | */ 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class RestoreIPAddresses { 12 | public List Restore(String ip) { // TC: O(3^4)?, SC: O(4) 13 | List res = new ArrayList<>(); 14 | char[] cur = new char[ip.length() + 4]; 15 | dfs(0, 0, cur, ip.toCharArray(), res); 16 | return res; 17 | } 18 | 19 | private void dfs(int lvl, int offset, char[] cur, char[] ip, List res) { 20 | if (lvl == 4) { 21 | if (lvl + offset == ip.length + 4) { 22 | res.add(new String(cur, 0, cur.length - 1)); 23 | } 24 | return; 25 | } 26 | 27 | if (offset < ip.length) { 28 | cur[lvl + offset] = ip[offset]; 29 | cur[lvl + offset + 1] = '.'; 30 | dfs(lvl + 1, offset + 1, cur, ip, res); 31 | } 32 | 33 | if (offset + 1 < ip.length && ip[offset] != '0') { 34 | cur[lvl + offset] = ip[offset]; 35 | cur[lvl + offset + 1] = ip[offset + 1]; 36 | cur[lvl + offset + 2] = '.'; 37 | dfs(lvl + 1, offset + 2, cur, ip, res); 38 | } 39 | 40 | if (offset + 2 < ip.length) { 41 | char a = ip[offset], b = ip[offset+1], c = ip[offset+2]; 42 | if (a == '1' || a == '2' && (b < '5' || b == '5' && c < '6')) { 43 | cur[lvl + offset] = a; 44 | cur[lvl + offset + 1] = b; 45 | cur[lvl + offset + 2] = c; 46 | cur[lvl + offset + 3] = '.'; 47 | dfs(lvl + 1, offset + 3, cur, ip, res); 48 | } 49 | } 50 | 51 | } 52 | 53 | public static void main(String[] args) { 54 | RestoreIPAddresses ria = new RestoreIPAddresses(); 55 | System.out.println(ria.Restore("0000")); // [0.0.0.0] 56 | System.out.println(ria.Restore("25525511135")); // [255.255.11.135, 255.255.111.35] 57 | System.out.println(ria.Restore("012345")); // [0.1.23.45, 0.1.234.5, 0.12.3.45, 0.12.34.5, 0.123.4.5] 58 | System.out.println(ria.Restore("123456789")); // [123.45.67.89] 59 | System.out.println(ria.Restore("12345678")); // [1.234.56.78, 12.34.56.78, 123.4.56.78, 123.45.6.78, 123.45.67.8] 60 | System.out.println(ria.Restore("1234567")); // [1.23.45.67, 1.234.5.67, 1.234.56.7, 12.3.45.67, 12.34.5.67, 12.34.56.7, 123.4.5.67, 123.4.56.7, 123.45.6.7] 61 | System.out.println(ria.Restore("255255111354")); // [] Error: too long 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Solutions/String and Array/394. Decode String.md: -------------------------------------------------------------------------------- 1 | # [394. Decode String](https://leetcode.com/problems/decode-string/) 2 | 3 | ## two stacks (0ms, 42 mb) 4 | TC: O(n), SC: O(n) 5 | ### 思路 6 | 1. define cur SB, sb stack, number stack 7 | 2. see '[': push number to number stack, cur sb to sb stack, reset sb stack 8 | 3. all number chars append to cur 9 | 3. see ']': poll number, poll from sb stack, concatenate: sb from stack + num*curstack ==> cur stack 10 | 11 | ### use array as stack, 0ms, 100%, 40.5mb, 92.02% 12 | use array as tack, top index inclusive: 13 |
14 | 0.        isEmpty  : top = -1; top = 0 means there's one element in stack: stack[0];
15 | 1. offerFirst/push : stack[++top] = val;
16 | 2.  peekFirst/peek : stack[top]
17 | 3.  pollFirst/pop  : stack[top--]/top--;
18 | 
19 | 20 | ```java 21 | class Solution { 22 | public String decodeString(String s) { 23 | int n = s.length(), t1 = -1, t2 = -1, num = 0; 24 | StringBuilder[] s2 = new StringBuilder[n/2]; 25 | int[] s1 = new int[n/2]; 26 | StringBuilder cur = new StringBuilder(); 27 | 28 | for (int i = 0; i < n; i++) { 29 | char c = s.charAt(i); 30 | if (c >= '0' && c <= '9') num = num * 10 + c - '0'; 31 | else if (c == '[') { 32 | s1[++t1] = num; num = 0; 33 | s2[++t2] = cur; cur = new StringBuilder(); 34 | } else if (c == ']') { 35 | StringBuilder temp = new StringBuilder(); 36 | for (int cnt = s1[t1--]; cnt > 0; cnt--) temp.append(cur); 37 | cur = s2[t2--].append(temp); 38 | } else cur.append(c); // normal chars 39 | } 40 | 41 | return cur.toString(); 42 | } 43 | } 44 | ``` 45 | 46 | ## Recursion 47 | TC: O(n), SC: O(depth of []) on call stack 48 | 49 | ### 思路 50 | 1. for numbers, accumulate them 51 | 2. see [, let next level of recursion handle it 52 | 1. num * result between [] from next level, append to current level 53 | 3. see ], return cur result to upper level 54 | 4. normal chars, just append 55 | ```java 56 | class Solution { 57 | int idx; 58 | public String decodeString(String s) { 59 | idx = 0; 60 | return helper(s).toString(); 61 | } 62 | 63 | private StringBuilder helper(String s) { 64 | StringBuilder sb = new StringBuilder(); 65 | 66 | int num = 0; 67 | while (idx < s.length()) { 68 | char c = s.charAt(idx++); 69 | if (c >= '0' && c <= '9') num = num * 10 + c - '0'; 70 | else if (c == '[') { 71 | for (StringBuilder tmp = helper(s); num > 0; num--) 72 | sb.append(tmp); 73 | } else if (c ==']') return sb; 74 | else sb.append(c); 75 | } 76 | 77 | return sb; 78 | } 79 | } 80 | ``` -------------------------------------------------------------------------------- /SortNumbersInThreeStacks.java: -------------------------------------------------------------------------------- 1 | /* 2 | Given one stack with integers, sort it with two additional stacks (total 3 stacks). 3 | 4 | After sorting the original stack should contain the sorted integers and 5 | from top to bottom the integers are sorted in ascending order. 6 | 7 | Assumptions: 8 | The given stack is not null. 9 | The time complexity should be O(n log n). 10 | */ 11 | 12 | 13 | import java.util.LinkedList; 14 | 15 | public class SortNumbersInThreeStacks { 16 | public void sort(LinkedList s1) { // 5*nlogn ==> O(nlogn) 17 | LinkedList s2 = new LinkedList<>(); 18 | LinkedList s3 = new LinkedList<>(); 19 | sort(s1, s2, s3, s1.size()); // sort top s1.size() values in s1 in ascending order from top to bottom 20 | } 21 | 22 | private void sort(LinkedList s1, LinkedList s2, LinkedList s3, int len) { 23 | if (len <= 1) return; 24 | int mid1 = len / 2, mid2 = len - mid1; 25 | 26 | for (int i = 0; i < mid1; i++) 27 | s2.offerFirst(s1.pollFirst()); 28 | 29 | // the key is to sort s2 and s1, the sequence of 2nd and 3rd stack doesn't matter 30 | // sort(s2, s3, s1, mid1); will also work 31 | // sort(s1, s3, s2, mid2); will also work 32 | // Below also works 33 | // sort(s1, s2, s3, mid2); sort s1 first 34 | // sort(s2, s1, s3, mid1); sort s2 next 35 | sort(s2, s1, s3, mid1); // sort top mid1 values in s2 in ascending order from top to bottom 36 | sort(s1, s2, s3, mid2);// sort top mid2 values in s1 in ascending order from top to bottom 37 | 38 | int i = 0, j = 0; 39 | 40 | while (i < mid1 && j < mid2) 41 | if (s2.peekFirst() < s1.peekFirst()) { 42 | s3.offerFirst(s2.pollFirst()); 43 | i++; 44 | } else { 45 | s3.offerFirst(s1.pollFirst()); 46 | j++; 47 | } 48 | 49 | for (; i < mid1; i++) s3.offerFirst(s2.pollFirst()); // special use of for loop in order to code this in one line 50 | for (; j < mid2; j++) s3.offerFirst(s1.pollFirst()); 51 | 52 | for (int k = 0; k < len; k++) s1.offerFirst(s3.pollFirst()); 53 | } 54 | 55 | public static void main(String[] args) { 56 | SortNumbersInThreeStacks sn3 = new SortNumbersInThreeStacks(); 57 | 58 | int[] res = new int[]{3, 8, 4, 5, 1, 7, 2, 6}; 59 | LinkedList s1 = new LinkedList<>(); 60 | 61 | for (int v : res) 62 | s1.offerFirst(v); // Add test data from int[] res to stack 63 | 64 | sn3.sort(s1); 65 | 66 | while (!s1.isEmpty()) 67 | System.out.println(s1.pollFirst()); // print out sorted data from stack 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /Solutions/String and Array/727. Minimum Window Subsequence.md: -------------------------------------------------------------------------------- 1 | # [727. Minimum Window Subsequence](https://leetcode.com/problems/minimum-window-subsequence/) 2 | 3 | ## Two Pointers (12ms, 85.38%) 4 | ```java 5 | class Solution { // (10ms, https://leetcode.com/submissions/detail/761619584/) 6 | public String minWindow(String s1, String s2) { 7 | int start = 0, len = s1.length() + 1; // default len to max value 8 | for(int i = 0, j = 0; i < s1.length(); i++) { 9 | if (s1.charAt(i) == s2.charAt(j) && ++j == s2.length()) { // we found a complete match for s2 10 | int end = i + 1; // exclusive 11 | for (j--; j >= 0;) if (s1.charAt(i--) == s2.charAt(j)) j--; 12 | i++;j++; 13 | if (end - i < len) len = end - (start = i); 14 | } 15 | } 16 | return len == s1.length() + 1 ? "" : s1.substring(start, start + len); 17 | } 18 | } 19 | ``` 20 | 21 | ## State Machine (21 ms, 64.82%) 22 | 23 | ```java 24 | class Solution { 25 | public String minWindow(String s, String t) { 26 | int n = s.length(), m = t.length(); 27 | int[][] next = new int[n + 1][26]; 28 | for (var a : next) Arrays.fill(a, -1); 29 | 30 | for (int i = n - 1; i >= 0; i--) { 31 | System.arraycopy(next[i + 1], 0, next[i], 0, 26); 32 | next[i][s.charAt(i) - 'a'] = i; 33 | } 34 | 35 | int start = 0, len = n + 1; 36 | for (int i = 0; i < n; i++) { 37 | if (s.charAt(i) != t.charAt(0)) continue; 38 | 39 | int idx = next[i][t.charAt(0) - 'a']; 40 | for (int j = 1; j < m; j++) 41 | if ((idx = next[idx + 1][t.charAt(j) - 'a']) == -1) 42 | break; 43 | 44 | if (idx == -1) break; 45 | 46 | if (idx - i + 1 < len) len = idx + 1 - (start = i); 47 | } 48 | 49 | return len == n + 1 ? "" : s.substring(start, start + len); 50 | } 51 | } 52 | ``` 53 | 54 | ## DP 55 | ```java 56 | class Solution { 57 | public String minWindow(String s, String t) { 58 | int n = s.length(), m = t.length(); 59 | int[][] dp = new int[m + 1][n + 1]; 60 | 61 | // init for next step to take (when taking from dp[i-1][j-1]) 62 | for (int j = 0; j <= n; j++) dp[0][j] = j + 1; 63 | 64 | for (int i = 1; i <= m; i++) for (int j = 1; j <= n; j++) 65 | dp[i][j] = s.charAt(j-1) == t.charAt(i-1) ? dp[i-1][j-1] : dp[i][j-1]; 66 | 67 | int start = 0, len = n + 1; 68 | for (int j = 1; j <= n; j++) 69 | if (dp[m][j] != 0 && j - dp[m][j] + 1 < len) 70 | len = j - (start = dp[m][j] - 1); 71 | 72 | return len == n + 1 ? "" : s.substring(start, start + len); 73 | } 74 | } 75 | ``` -------------------------------------------------------------------------------- /FlipGameII.java: -------------------------------------------------------------------------------- 1 | /* 2 | You are playing the following Flip Game with your friend: Given a string that contains only these two characters: + and -, 3 | you and your friend take turns to flip two consecutive "++" into "--". 4 | The game ends when a person can no longer make a move and therefore the other person will be the winner. 5 | Write a function to determine if the starting player can guarantee a win. 6 | 7 | For example, given s = "++++", return true. 8 | The starting player can guarantee a win by flipping the middle "++" to become "+--+". 9 | Sample Results: 10 | +++ true 11 | ++++ true 12 | +++++ false 13 | ++++++ true 14 | +++++++ true 15 | ++++++++ true 16 | +++++++++ false 17 | ++++++++++ false 18 | +++++++++++ false 19 | ++++++++++++ true 20 | +++++++++++++ false 21 | ++++++++++++++ false 22 | +++----+++--++ true 23 | */ 24 | 25 | import java.util.ArrayList; 26 | import java.util.List; 27 | 28 | public class FlipGameII { 29 | public boolean canWin(String s) { 30 | char[] a = s.toCharArray(); 31 | for (int i : validIndices(a)) { 32 | a[i] = a[i + 1] = '-'; 33 | if (!friendCanWin(a, 1)) return true; // I flip first, if there's one flip to guarantee friend can't win, I win, otherwise I lose 34 | a[i] = a[i + 1] = '+'; 35 | } 36 | return false; 37 | } 38 | 39 | private boolean friendCanWin(char[] a, int hand) { // hand 0 means self and hand 1 means friend 40 | List candidates = validIndices(a); 41 | if (candidates.size() == 0) 42 | return hand % 2 == 0; 43 | 44 | for (int i : candidates) { 45 | a[i] = a[i + 1] = '-'; 46 | boolean friendCanWin = friendCanWin(a, hand + 1); 47 | a[i] = a[i + 1] = '+'; // need to recover first before return so that I can try another flip in main method 48 | if (friendCanWin) return true; 49 | } 50 | return false; 51 | } 52 | 53 | private List validIndices(char[] a) { 54 | List res = new ArrayList<>(); 55 | for (int i = 0; i < a.length - 1; i++) 56 | if (a[i] == '+' && a[i + 1] == '+') 57 | res.add(i); 58 | return res; 59 | } 60 | 61 | public static void main(String[] args) { 62 | FlipGameII fg = new FlipGameII(); 63 | for (int i = 3; i < 15; i++) { 64 | String s = "+".repeat(i); 65 | System.out.printf("%-15s%s\n", s, fg.canWin(s)); 66 | } 67 | String s = "+++----+++--++"; 68 | System.out.printf("%-15s%s\n", s, fg.canWin(s)); // true 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Solutions/Monotonic Stack/84. Largest Rectangle in Histogram.md: -------------------------------------------------------------------------------- 1 | [84. Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/) 2 | 3 | ## Array as mono-stack (7 ms, faster than 99.95%) 4 | TC: O(n), SC: O(n) 5 | ```java 6 | class Solution { 7 | public int largestRectangleArea(int[] a) { 8 | 9 | int max = 0, n = a.length, top = 0, cur; 10 | int[] stack = new int[n + 2];stack[0] = -1; 11 | for (int i = 0; i <= n; stack[++top] = i++) 12 | while (top > 0 && (i == n ? 0 : a[i]) < a[stack[top]]) 13 | if((cur = a[stack[top--]] * (i - stack[top] - 1)) > max) 14 | max = cur; 15 | 16 | return max; 17 | 18 | } 19 | } 20 | ``` 21 | 22 | ## mono-stack 23 | TC/SC: O(n) 24 | ```java 25 | class Solution { 26 | public int largest(int[] a) { 27 | int res = 0; 28 | Deque stack = new ArrayDeque<>();stack.offerFirst(-1); 29 | for (int i = 0; i <= a.length; stack.offerFirst(i++)) 30 | while (stack.peekFirst() != -1 && a[stack.peekFirst()] > (i == a.length ? 0 : a[i])) 31 | res = Math.max(res, a[stack.pollFirst()] * (i - stack.peekFirst() - 1)); 32 | 33 | return res; 34 | } 35 | } 36 | ``` 37 | #### same idea, more line of codes 38 | ```java 39 | class Solution { 40 | public int largest(int[] a) { 41 | int res = 0; 42 | Deque stack = new ArrayDeque<>(); 43 | for (int i = 0; i <= a.length; stack.offerFirst(i++)) { 44 | while (!stack.isEmpty() && a[stack.peekFirst()] > (i == a.length ? 0 : a[i])) { 45 | int h = a[stack.pollFirst()]; 46 | int left = stack.isEmpty() ? 0 : stack.peekFirst() + 1; 47 | res = Math.max(res, (i - left) * h); 48 | } 49 | } 50 | return res; 51 | } 52 | } 53 | ``` 54 | 55 | ## DP 56 | ```java 57 | class Solution { 58 | public int largestRectangleArea(int[] A) { // TC: O(n), SC: O(n) 59 | int max = 0; 60 | int[] lessFromLeft = new int[A.length]; // idx of the first bar the left that is lower than current 61 | int[] lessFromRight = new int[A.length]; // idx of the first bar the right that is lower than current 62 | lessFromRight[A.length - 1] = A.length; 63 | lessFromLeft[0] = -1; 64 | 65 | for (int i = 1; i < A.length; i++) { 66 | int p = i - 1; 67 | while (p >= 0 && A[p] >= A[i]) p = lessFromLeft[p]; 68 | lessFromLeft[i] = p; 69 | } 70 | 71 | for (int i = A.length - 2; i >= 0; i--) { 72 | int p = i + 1; 73 | while (p < A.length && A[p] >= A[i]) p = lessFromRight[p]; 74 | lessFromRight[i] = p; 75 | } 76 | 77 | for (int i = 0; i < A.length; i++) { 78 | max = Math.max(max, A[i] * (lessFromRight[i] - lessFromLeft[i] - 1)); 79 | } 80 | return max; 81 | } 82 | } 83 | ``` --------------------------------------------------------------------------------