传送门:题目39 题目40
我觉得比较好的题解:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/
观察发现[2 2 3]、[2 3 2]、[3 2 2]这几种是重复的,因此需要去重,去重前先排序:
去重的规则,首先设置一个搜索的起点,因为一个数可以多次使用,故下一个点仍可以从这个搜索起点开始。但是只能向后搜索,因为前面的点已经当过搜索起点了。
为了提高速度,也可以稍微剪枝处理一下:如[6 7 8], target = 12。 start = 6,6 + 7 > 12,那么6 + 8也肯定大于12,就不用往下搜了。
#include#include using namespace std; class Solution { private: vector<int> candidates; /*无重复元素数组*/ vector int>> res; /*输出答案*/ vector<int> path; /*满足题意组合*/ public: void dfs(int start, int target){ if (target == 0){ res.push_back(path); return ; } for(int i = start; i < candidates.size() && target - candidates[i] >= 0; i++){/*剪枝*/ path.push_back(candidates[i]); dfs(i, target - candidates[i]); /*递归*/ path.pop_back(); } } vector int>> combinationSum(vector<int>& candidates, int target) { sort(candidates.begin(), candidates.end()); /*用于去重,防止出现[2,2,3]、[3,2,2]*/ this->candidates = candidates; /*成员函数内部指向调用的对象*/ dfs(0, target); return res; }
那么每次确定搜索起点之后,下一个节点只能在搜索起点之后了,如下
dfs(i + 1, target - candidates[i]);
但是还会出现一个问题Candidates = [1,1,2,5,6,7,10],target = 8。结果会有两个[1 7]、[1 2 5]
解决的方法:笨一点可以用vector的去重,vector去重有两种方法:一、先转化为set,再换位vector。二、利用unique和earse
/*vector去重*/ set<int>s(vec.begin(), vec.end()); vec.assign(s.begin(), s.end());
sort(vec.begin(), vec.end());
vec.erase(unique(vec.begin(), vec.end()), vec.end());
注意:unique()函数将相邻且重复的元素放到vector的尾部 然后返回指向第一个重复元素的迭代器。那么我们可以用erase函数擦除从这个元素到最后元素的所有的元素。
这个方法的优点费,可以在39的基础上修改下:
#include#include #include <set> using namespace std; class Solution { private: vector<int> candidates; vector int>> res; vector<int> path; public: void dfs(int start, int target){ if (target == 0){ res.push_back(path); return ; } for(int i = start; i < candidates.size() && target - candidates[i] >= 0; i++){ if (i > start && candidates[i] == candidates[i - 1]) continue; /*eg 1 2 2 5, [1 2 5]只会出现一次*/ path.push_back(candidates[i]); dfs(i + 1, target - candidates[i]); path.pop_back(); } } vector int>> combinationSum2(vector<int>& candidates, int target) { sort(candidates.begin(), candidates.end()); this->candidates = candidates; dfs(0, target); return res; } };
到此为止,就完了。回溯法还得多练练手,反复多看看。