我在leetcode中遇到了一个问题,我看了其他人使用DP的解决方案,但是有些我无法理解,希望您能给我一些提示。
问题是:给定一个仅包含正整数的非空数组,找出有多少种方法来选择其中一些总和等于目标 S 的整数。
解决方案是:
int findTargetSumWays(vector<int>& nums, int S)
{
int n = nums.size();
vector<int> dp(S+1, 0);
dp[0] = 1;
for(int i=0; i<n; i++)
for(int j=S; j>=nums[i]; j--)
//for(int j=nums[i]; j<=S; j++) //why it is wrong?
{
dp[j] += dp[j-nums[i]];
}
return dp[S];
}
在代码中,第二个循环从 S 向下计数到 nums[i],但为什么它不能从 nums[i] 向上计数到 S?我知道如果向上计数,结果会比答案大得多,但我无法弄清楚向上计数的本质问题。
任何帮助不胜感激!
由于nums[i]
保证为正数,因此在以下行中:
dp[j] += dp[j-nums[i]]
数组中较大索引处的元素正在根据同一数组中较小索引处的元素值进行修改。
由于j
开始时为高并递减,因此在每次迭代中,可以保证需要读取的值(索引小于 j(不是已覆盖的值(大于 j 的索引(。
相反,如果您从低j
开始并递增它,那么您最终会覆盖稍后将在循环中读取的值。然后,它们将具有不正确的值并产生错误的答案。
在就地对数组进行操作的算法中,这种事情是一个非常常见的考虑因素。
当第二个循环向下计数时,您计算所有可能性,以求和数组的元素并获得目标S
其中数组的每个元素只能取一次。但是,当第二个循环向上计数时,您会计算数组的每个元素都可以被任意次数获取的可能性。所以第二个数字大于或等于第一个数字。