leetcode 377. 组合总和 Ⅳ


没写出来🤡
class Solution {
public:
//当1 ≤ i ≤ target 时,如果存在一种排列,其中的元素之和等于 i,则该排列的最后一个元素一定是数组 nums 中的一个元素。
//假设该排列的最后一个元素是 num,则一定有 num ≤ i,对于元素之和等于 i−num 的每一种排列,在最后添加 num 之后即可得到一个元素之和等于 i 的排列,
//因此在计算 dp[i] 时,应该计算所有的 dp[i−num] 之和。
int combinationSum4(vector<int>& nums, int target) {
vector<int> dp(target+1);//dp[i]代表 i 可由nums元素组合的个数
dp[0] = 1;//只有当不选取任何元素时,元素之和才为 0,因此只有 1 种方案。
for(int i = 1;i <= target;++i){
//遍历 i 从 1 到 target,对于每个 i,进行如下操作:
for(int &num : nums){
//遍历数组 nums 中的每个元素 num,当 num≤i 时,将 dp[i−num] 的值加到 dp[i]。
if(num <= i && dp[i-num] < INT_MAX - dp[i]){
dp[i] += dp[i-num];
}
}
}
return dp[target];
}
};
如果给定的数组中含有负数,则会导致出现无限长度的排列。
例如,假设数组 nums 中含有正整数 a 和负整数 −b(其中 a>0,b>0,−b<0),则有 a×b+(−b)×a=0,对于任意一个元素之和等于 target 的排列,在该排列的后面添加 b 个 a 和 a 个 −b 之后,得到的新排列的元素之和仍然等于 target,而且还可以在新排列的后面继续 b 个 a 和 a 个 −b。因此只要存在元素之和等于 target 的排列,就能构造出无限长度的排列。
如果允许负数出现,则必须限制排列的最大长度,避免出现无限长度的排列,才能计算排列数。
关于INT_MAX的问题,出错的用例如下: [10,20,30,40,50,60,70,80,90,100,110,120,130,140,150,160,170,180,190,200,210,220,230,240,250,260,270,280,290,300,310,320,330,340,350,360,370,380,390,400,410,420,430,440,450,460,470,480,490,500,510,520,530,540,550,560,570,580,590,600,610,620,630,640,650,660,670,680,690,700,710,720,730,740,750,760,770,780,790,800,810,820,830,840,850,860,870,880,890,900,910,920,930,940,950,960,970,980,990,111] target=999
这个用例的答案只有一种,就是9个111 。可以看到前面n-1个数都是10的倍数,是不可能得到和为999的。 但是dp计算的过程中会计算和为0-999所有数字。例如计算dp[990], 排列数目会有很多,可能越界。
最符合理论的解法是:使用unsigned long long, 这样完全满足传递方程, 保证中间计算值不越界。
官方的解法有偷巧的地方,因为最终结果保证不超过INT_MAX, 所以超过就不传递了。实际确实也不传递,假设dp[990] > INT_MAX, dp[999] 实际无法通过dp[990]传递,因为nums里面没有一个值是9.
总结:dp中间值可能大于INT_MAX, 但是目标值是小于INT_MAX的。测试用例特殊,目标值实际不需要中间值(大于INT_MAX)的传递。
class Solution {
public:
int dfs(vector<int>& nums,int target,vector<int> &memo){
if(target == 0) return 1;
if(memo[target] != -1) return memo[target];//之前算过
memo[target] = 0;
for(int &num : nums){
if(num <= target){
memo[target] += dfs(nums,target-num,memo);
}
}
return memo[target];
}
int combinationSum4(vector<int>& nums, int target) {
vector<int> memo(target+1,-1);
return dfs(nums,target,memo);
}
};
浙公网安备 33010602011771号