我正在做正数的子集和问题。在典型的DP解决方案中,我们使用表格[n + 1] [sum + 1]的2D DP表,其中n是集合中元素的数量,sum
是目标总和。现在,我想对其进行优化以仅使用一行,因为所有行都使用上一行的结果。为此,我提出了一个解决方案:
boolean DP[] = new boolean[sum+1];
DP[0] = true;
for(int i = 0; i < arr.length; i++) {
for(int j = arr[i]; j <= sum; j++) {
DP[j] = DP[j] || DP[j-arr[i]];
}
}
return DP[sum];
此代码无法通过某些测试用例。但是,如果我将内部循环更改为向后迭代,则为:
for(int j = sum; j >= arr[i]; j--)
然后此代码通过所有测试用例。我无法弄清楚向后迭代产生的差异。我希望能得到解释。
答案 0 :(得分:1)
一个简单的示例,可以帮助您理解
arr = {1, 4}, sum = 7
如果要迭代转发,则是第一次迭代i = 0
dp[0] = true
for (int j = arr[0]; j <= sum; j++){
}
这是此循环内的步骤:
dp[1] = dp[1] || dp[1 - 1]; //true as dp[0] = true
dp[2] = dp[2] || dp[2 - 1]; // also true, as previous step, we update dp[1] = true
....
dp[7] = dp[7] || dp[7 - 1]; // true for similar reason
因此,对于第一次迭代,所有元素都是正确的
如果要迭代向后,则第一次迭代i = 0
dp[0] = true
for (int j = sum; j >= arr[0]; j--){
}
这是此循环内的步骤:
dp[7] = dp[7] || dp[7 - 1]; //false
dp[6] = dp[6] || dp[6 - 1]; // also false,
....
dp[1] = dp[1] || dp[1 - 1]; // true as dp[0] = true
因此,对于第一次迭代,我们要的是dp[1]
和dp[0] = true
之外的所有东西。