Skip to content
Merged
6 changes: 3 additions & 3 deletions problems/0123.买卖股票的最佳时机III.md
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,9 @@ class Solution {

for (int i = 1; i < len; i++) {
dp[i][1] = Math.max(dp[i - 1][1], -prices[i]);
dp[i][2] = Math.max(dp[i - 1][2], dp[i][1] + prices[i]);
dp[i][3] = Math.max(dp[i - 1][3], dp[i][2] - prices[i]);
dp[i][4] = Math.max(dp[i - 1][4], dp[i][3] + prices[i]);
dp[i][2] = Math.max(dp[i - 1][2], dp[i - 1][1] + prices[i]);
dp[i][3] = Math.max(dp[i - 1][3], dp[i - 1][2] - prices[i]);
dp[i][4] = Math.max(dp[i - 1][4], dp[i - 1][3] + prices[i]);
}

return dp[len - 1][4];
Expand Down
35 changes: 32 additions & 3 deletions problems/0198.打家劫舍.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,36 @@ class Solution {
}
}

// 空间优化 dp数组只存与计算相关的两次数据
// 使用滚动数组思想,优化空间
// 分析本题可以发现,所求结果仅依赖于前两种状态,此时可以使用滚动数组思想将空间复杂度降低为3个空间
class Solution {
public int rob(int[] nums) {

int len = nums.length;

if (len == 0) return 0;
else if (len == 1) return nums[0];
else if (len == 2) return Math.max(nums[0],nums[1]);


int[] result = new int[3]; //存放选择的结果
result[0] = nums[0];
result[1] = Math.max(nums[0],nums[1]);


for(int i=2;i<len;i++){

result[2] = Math.max(result[0]+nums[i],result[1]);

result[0] = result[1];
result[1] = result[2];
}

return result[2];
}
}

// 进一步对滚动数组的空间优化 dp数组只存与计算相关的两次数据
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) {
Expand All @@ -151,11 +180,11 @@ class Solution {
// 优化空间 dp数组只用2格空间 只记录与当前计算相关的前两个结果
int[] dp = new int[2];
dp[0] = nums[0];
dp[1] = nums[0] > nums[1] ? nums[0] : nums[1];
dp[1] = Math.max(nums[0],nums[1]);
int res = 0;
// 遍历
for (int i = 2; i < nums.length; i++) {
res = (dp[0] + nums[i]) > dp[1] ? (dp[0] + nums[i]) : dp[1];
res = Math.max((dp[0] + nums[i]) , dp[1] );
dp[0] = dp[1];
dp[1] = res;
}
Expand Down
61 changes: 60 additions & 1 deletion problems/0416.分割等和子集.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,12 @@ class Solution {
for(int i = 0; i < n; i++) {
for(int j = target; j >= nums[i]; j--) {
//物品 i 的重量是 nums[i],其价值也是 nums[i]
dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i]);
dp[j] = Math.max(dp[j], dp[j - nums[i]] + nums[i]);
}

//剪枝一下,每一次完成內層的for-loop,立即檢查是否dp[target] == target,優化時間複雜度(26ms -> 20ms)
if(dp[target] == target)
return true;
}
return dp[target] == target;
}
Expand Down Expand Up @@ -294,6 +298,61 @@ false true false false false true true false false false false false
false true false false false true true false false false false true
false true false false false true true false false false true true
```
二維數組整數版本
```Java
class Solution {
public boolean canPartition(int[] nums) {
//using 2-D DP array.
int len = nums.length;
//check edge cases;
if(len == 0)
return false;

int sum = 0;
for (int num : nums)
sum += num;
//we only deal with even numbers. If sum is odd, return false;
if(sum % 2 == 1)
return false;

int target = sum / 2;
int[][] dp = new int[nums.length][target + 1];

// for(int j = 0; j <= target; j++){
// if(j < nums[0])
// dp[0][j] = 0;
// else
// dp[0][j] = nums[0];
// }

//initialize dp array
for(int j = nums[0]; j <= target; j++){
dp[0][j] = nums[0];
}

for(int i = 1; i < len; i++){
for(int j = 0; j <= target; j++){
if (j < nums[i])
dp[i][j] = dp[i - 1][j];
else
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
}
}

//print out DP array
// for(int x : dp){
// System.out.print(x + ",");
// }
// System.out.print(" "+i+" row"+"\n");
return dp[len - 1][target] == target;
}
}
//dp数组的打印结果 for test case 1.
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
0, 1, 1, 1, 1, 5, 6, 6, 6, 6, 6, 6,
0, 1, 1, 1, 1, 5, 6, 6, 6, 6, 6, 11,
0, 1, 1, 1, 1, 5, 6, 6, 6, 6, 10, 11,
```

### Python:
```python
Expand Down
52 changes: 51 additions & 1 deletion problems/0718.最长重复子数组.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,57 @@ public:

而且为了让 `if (dp[i][j] > result) result = dp[i][j];` 收集到全部结果,两层for训练一定从0开始遍历,这样需要加上 `&& i > 0 && j > 0`的判断。

相对于版本一来说还是多写了不少代码。而且逻辑上也复杂了一些。 优势就是dp数组的定义,更直观一点。
对于基础不牢的小白来说,在推导出转移方程后可能疑惑上述代码为什么要从`i=0,j=0`遍历而不是从`i=1,j=1`开始遍历,原因在于这里如果不是从`i=0,j=0`位置开始遍历,会漏掉如下样例结果:
```txt
nums1 = [70,39,25,40,7]
nums2 = [52,20,67,5,31]
```

当然,如果你愿意也可以使用如下代码,与上面那个c++是同一思路:
```java
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int[][] result = new int[len1][len2];

int maxresult = Integer.MIN_VALUE;

for(int i=0;i<len1;i++){
if(nums1[i] == nums2[0])
result[i][0] = 1;
if(maxresult<result[i][0])
maxresult = result[i][0];
}

for(int j=0;j<len2;j++){
if(nums1[0] == nums2[j])
result[0][j] = 1;
if(maxresult<result[0][j])
maxresult = result[0][j];
}

for(int i=1;i<len1;i++){
for(int j=1;j<len2;j++){

if(nums1[i]==nums2[j])
result[i][j] = result[i-1][j-1]+1;

if(maxresult<result[i][j])
maxresult = result[i][j];

}

}

return maxresult;
}
}
```

对于小白来说一定要明确dp数组中初始化的数据是什么

整体而言相对于版本一来说还是多写了不少代码。而且逻辑上也复杂了一些。 优势就是dp数组的定义,更直观一点。

## 其他语言版本

Expand Down