diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index 73faaea7..6978754f 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -1890,12 +1890,12 @@ public int lengthOfLIS(int[] nums) { } ``` -以上解法的时间复杂度为 O(n2) ,可以使用二分查找使得时间复杂度降低为 O(nlogn)。定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素,例如对于数组 [4,5,6,3],有 +以上解法的时间复杂度为 O(n2) ,可以使用二分查找使得时间复杂度降低为 O(nlogn)。定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素,例如对于数组 [4,5,6,3],有 ```html len = 1 : [4], [5], [6], [3] => tails[0] = 3 len = 2 : [4, 5], [5, 6] => tails[1] = 5 -len = 3 : [4, 5, 6] => tails[2] = 6 +len = 3 : [4, 5, 6] => tails[2] = 6 ``` 对于一个元素 x,如果它大于 tails 数组所有的值,那么把它添加到 tails 后面;如果 tails[i-1] < x <= tails[i],那么更新 tails[i] = x 。 @@ -1907,22 +1907,22 @@ public int lengthOfLIS(int[] nums) { int n = nums.length; int[] tails = new int[n]; int size = 0; - for(int i = 0; i < n; i++){ - int idx = binarySearch(tails, 0, size, nums[i]); - tails[idx] = nums[i]; - if(idx == size) size++; + for (int i = 0; i < n; i++) { + int index = binarySearch(tails, 0, size, nums[i]); + tails[index] = nums[i]; + if (index == size) size++; } return size; } -private int binarySearch(int[] nums, int sIdx, int eIdx, int key){ - while(sIdx < eIdx){ - int mIdx = sIdx + (eIdx - sIdx) / 2; - if(nums[mIdx] == key) return mIdx; - else if(nums[mIdx] > key) eIdx = mIdx; - else sIdx = mIdx + 1; +private int binarySearch(int[] nums, int first, int last, int key) { + while (first < last) { + int mid = first + (last - first) / 2; + if (nums[mid] == key) return mid; + else if (nums[mid] > key) last = mid; + else first = mid + 1; } - return sIdx; + return first; } ``` @@ -1930,6 +1930,19 @@ private int binarySearch(int[] nums, int sIdx, int eIdx, int key){ [Leetcode : 376. Wiggle Subsequence (Medium)](https://leetcode.com/problems/wiggle-subsequence/description/) +```html +Input: [1,7,4,9,2,5] +Output: 6 +The entire sequence is a wiggle sequence. + +Input: [1,17,5,10,13,15,10,5,16,8] +Output: 7 +There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8]. + +Input: [1,2,3,4,5,6,7,8,9] +Output: 2 +``` + 要求:使用 O(n) 时间复杂度求解。 使用两个状态 up 和 down。 @@ -2008,7 +2021,7 @@ public int knapsack(int W, int N, int[] weights, int[] values) { for (int j = W - 1; j >= weights[i]; j--) { dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weights[i]] + values[i]); } - for (int j = weights[i - 1] - 1; j >= 0; j--) { + for (int j = weights[i] - 1; j >= 0; j--) { dp[i][j] = dp[i - 1][j]; } } @@ -2048,6 +2061,14 @@ public int knapsack(int W, int N, int[] weights, int[] values) { [Leetcode : 416. Partition Equal Subset Sum (Medium)](https://leetcode.com/problems/partition-equal-subset-sum/description/) +```html +Input: [1, 5, 11, 5] + +Output: true + +Explanation: The array can be partitioned as [1, 5, 5] and [11]. +``` + 可以看成一个背包大小为 sum/2 的 0-1 背包问题,但是也有不同的地方,这里没有价值属性,并且背包必须被填满。 以下实现使用了空间优化。 @@ -2063,16 +2084,16 @@ public boolean canPartition(int[] nums) { } int W = sum / 2; boolean[] dp = new boolean[W + 1]; - int n = nums.length; - for(int i = 0; i <= W; i++) { - if(nums[0] == i) dp[i] = true; + for (int i = 0; i <= W; i++) { + if (nums[0] == i) { + dp[i] = true; + } } - for(int i = 1; i < n; i++) { - for(int j = W; j >= nums[i]; j--) { + for (int i = 1; i < nums.length; i++) { + for (int j = W; j >= nums[i]; j--) { dp[j] = dp[j] || dp[j - nums[i]]; } } - return dp[W]; } ``` @@ -2094,8 +2115,7 @@ public boolean wordBreak(String s, List wordDict) { dp[0] = true; for (int i = 1; i <= n; i++) { for (String word : wordDict) { - if (word.length() <= i - && word.equals(s.substring(i - word.length(), i))) { + if (word.length() <= i && word.equals(s.substring(i - word.length(), i))) { dp[i] = dp[i] || dp[i - word.length()]; } } @@ -2174,9 +2194,8 @@ Explanation: This are totally 4 strings can be formed by the using of 5 0s and 3 ```java public int findMaxForm(String[] strs, int m, int n) { if (strs == null || strs.length == 0) return 0; - int l = strs.length; int[][] dp = new int[m + 1][n + 1]; - for (int i = 0; i < l; i++) { + for (int i = 0; i < strs.length; i++) { String s = strs[i]; int ones = 0, zeros = 0; for (char c : s.toCharArray()) { @@ -2185,9 +2204,7 @@ public int findMaxForm(String[] strs, int m, int n) { } for (int j = m; j >= zeros; j--) { for (int k = n; k >= ones; k--) { - if (zeros <= j && ones <= k) { - dp[j][k] = Math.max(dp[j][k], dp[j - zeros][k - ones] + 1); - } + dp[j][k] = Math.max(dp[j][k], dp[j - zeros][k - ones] + 1); } } } @@ -2199,20 +2216,30 @@ public int findMaxForm(String[] strs, int m, int n) { [Leetcode : 322. Coin Change (Medium)](https://leetcode.com/problems/coin-change/description/) +```html +Example 1: +coins = [1, 2, 5], amount = 11 +return 3 (11 = 5 + 5 + 1) + +Example 2: +coins = [2], amount = 3 +return -1. +``` + 题目描述:给一些面额的硬币,要求用这些硬币来组成给定面额的钱数,并且使得硬币数量最少。硬币可以重复使用。 这是一个完全背包问题,完全背包问题和 0-1 背包问题在实现上唯一的不同是,第二层循环是从 0 开始的,而不是从尾部开始。 ```java public int coinChange(int[] coins, int amount) { + if (coins == null || coins.length == 0) return 0; + Arrays.sort(coins); int[] dp = new int[amount + 1]; Arrays.fill(dp, amount + 1); dp[0] = 0; for (int i = 1; i <= amount; i++) { - for (int j = 0; j < coins.length; j++) { - if (coins[j] <= i) { - dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); - } + for (int j = 0; j < coins.length && coins[j] <= i; j++) { + dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); } } return dp[amount] > amount ? -1 : dp[amount]; @@ -2243,11 +2270,12 @@ Therefore the output is 7. ```java public int combinationSum4(int[] nums, int target) { + if (nums == null || nums.length == 0) return 0; int[] dp = new int[target + 1]; dp[0] = 1; for (int i = 1; i <= target; i++) { for (int j = 0; j < nums.length; j++) { - if(nums[j] <= i) { + if (nums[j] <= i) { dp[i] += dp[i - nums[j]]; } } @@ -2285,7 +2313,7 @@ dp[i, j] = max(dp[i, j-1], prices[j] - prices[jj] + dp[i-1, jj]) { jj in range o ```java public int maxProfit(int k, int[] prices) { int n = prices.length; - if (k >= n/2) { + if (k >= n/2) { // 这种情况下该问题退化为普通的股票交易问题 int maxPro = 0; for (int i = 1; i < n; i++) { if (prices[i] > prices[i-1]) diff --git a/notes/算法.md b/notes/算法.md index b4d8893a..3a8a4843 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -975,7 +975,7 @@ public class BinarySearchST, Value> {

-BST 有一个重要性质,就是它的前序遍历结果递增排序。 +BST 有一个重要性质,就是它的中序遍历结果递增排序。