力扣-39(40)-组合总和I(II)

传送门:题目39  题目40


我觉得比较好的题解:https://leetcode-cn.com/problems/combination-sum/solution/hui-su-suan-fa-jian-zhi-python-dai-ma-java-dai-m-2/

力扣-39(40)-组合总和I(II)_第1张图片

 

 观察发现[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; /*无重复元素数组*/
    vectorint>> 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();
        }
    }
    vectorint>> 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;
    vectorint>> 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();
        } 
    }
    
    vectorint>> combinationSum2(vector<int>& candidates, int target) {
        sort(candidates.begin(), candidates.end());
        this->candidates = candidates;
        dfs(0, target);
        return res;
    }
};

到此为止,就完了。回溯法还得多练练手,反复多看看。

你可能感兴趣的:(力扣-39(40)-组合总和I(II))