一. 这题一开始想肯定回溯法, 一开始想了个顺其自然的思路,直接看代码能理解, 结果重复了.
//没有去重,报错
class Solution {
public:
vector<vector<int>> res;
void backtrace(int sum, vector<int> tmp, int target, vector<int> candidates) {
if (sum > target) {
return;
}
if (sum == target) {
res.push_back(tmp);
return;
}
for (int i = 0; i < candidates.size(); i++) {
sum += candidates[i];
tmp.push_back(candidates[i]);
backtrace(sum, tmp, target, candidates);
//回溯完成得把之前做的工作都去除.
sum -= candidates[i];
tmp.pop_back();
}
}
vector<vector<int>>combinationSum(vector<int>& candidates, int target) {
vector<int> tmp;
int sum = 0;
backtrace(sum, tmp, target, candidates);
return res;
}
};
二. 参考大神非常好的讲解, 感觉这篇写的回溯非常不错.
作者:leetcode
链接:https://leetcode-cn.com/circle/article/GV6eQ2/
1. 重复的原因每次backtrace里的for循环都从i=0开始,导致第一次的1,2和第二次的2,1重复(仔细理解一下,大概这个意思).
2. 解决办法大神的意思是设置一个start变量, i每次从start开始,这样不会出现1,2和2,1 这种情况,而是1,2和2,2这种情况.
//大神解法,用start变量限制只能找当前及其以后的元素
class Solution {
public:
vector<vector<int>> res;
void backtrace(int start, vector<int> tmp, int target, vector<int> candidates) {
//达到target,不是用sum,而是每次减对应值,看是否到0.
if (target < 0) {
return;
}
if (target == 0) {
res.push_back(tmp);
return;
}
for (int i = start; i < candidates.size(); i++) {
tmp.push_back(candidates[i]);
backtrace(i, tmp, target-candidates[i], candidates);
//回溯完成得把之前做的工作都去除.
tmp.pop_back();
}
}
vector<vector<int>>combinationSum(vector<int>& candidates, int target) {
vector<int> tmp;
backtrace(0, tmp, target, candidates);
return res;
}
};
三. 参考大神的动态规划, 因为大神说"随着我把组合总和的II、III、IV做完,尤其是到IV的时候,回溯算法就超时了,而IV恰好是用动态规划解决的,于是我就思考:能不能用动态规划
求解本题."
作者:chun-meng-da-xiao-yang
链接:https://leetcode-cn.com/problems/combination-sum/solution/chao-qiang-gifzhu-ni-shi-yong-dong-tai-gui-hua-qiu/
1. 总结: 求解一个值,需要求解上一个值,进而需要求解上上个值...,这种方法就是动态规划。重复的值只需要进行一次,而后再使用到这个值时,只需要将他的结果拿来适当增加即可。
//动态规划
// 由@pris_bupt提供
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
//dict[i]代表和为i的vector是啥.
unordered_map<int, set<vector<int>>>dict;
for (int i = 1; i <= target; i++)
for (int it : candidates)
if (i == it) dict[i].insert(vector<int>{it});
else if (i > it)
for (auto ivec : dict[i - it]) {
ivec.push_back(it);
sort(ivec.begin(), ivec.end());
if (dict[i].count(ivec) == 0)
dict[i].insert(ivec);
}
vector<vector<int>>ans;
for (auto it : dict[target]) ans.push_back(it);
return ans;
}