1 回溯法(超时)
根据题目,你会发现,本问题有几个性质
- 不同顺序为不同解(类比排列问题)——不宜用组合中的
first
技巧 - 输入无重复元素——不宜用sort+跳过重复元素技巧
- 问题的解可以包含重复元素——不宜用inPath技巧
可见,基于排列/组合/子集的三板斧技巧均不宜用在本问题中,此时回溯法基本退化成了穷举法,具体代码如下
class Solution {
private:
int size;
int count = 0;
public:
void backtrack(vector<int>& nums, int target, int sum) {
if (sum == target) {
count++;
return;
}
for (int i = 0; i < size; i++) {
if (sum + nums[i] > target) break;
backtrack(nums, target, sum + nums[i]);
}
}
int combinationSum4(vector<int>& nums, int target) {
size = nums.size();
sort(nums.begin(), nums.end());
backtrack(nums, target, 0);
return count;
}
};
结果超出时间限制
通过第三方IDE测试答案是正确的
2 动态规划(完全背包)
注意:Leetcode C++编译器对于两数加和可能的溢出直接会报错(个人IDE上的编译器可正常运行),因此防止两数加和溢出int,需加判断
Line 11: Char 35: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' (solution.cpp)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:20:35
dp[j] < INT_MAX - dp[j - nums[i]]
完整代码如下
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
int size = nums.size();
vector<int> dp(target + 1, 0);
dp[0] = 1;
for (int j = 0; j <= target; j++)
for (int i = 0; i < size; i++)
// 防止两数加和溢出>int需判断dp[j] < INT_MAX - dp[j - nums[i]]
if (j >= nums[i] && dp[j] < INT_MAX - dp[j - nums[i]])
dp[j] = dp[j] + dp[j - nums[i]];
return dp[target];
}
};