(LeetCode 39)组合总和 [DFS: 暴力搜索 + 剪枝 + 去重]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/STILLxjy/article/details/83627703

39. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:

输入: candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]

分析:
首先我们可以暴力枚举出所有的正确组合。但是会存在"重复"问题。如[2,2,3], [3,2,2],[2,3,2]…

如何去重呢?
对于重复的问题,是因为在某一解中我们已经先添加了candidates[i] , 然后再加入candidates[j] (i < j) ; 而在另一个解中是按照:先添加candidates[j] 后 加入 candidates[i] 所造成的。
所以为了防止重复解出现,我们只需规定: 在某一个可行解中,它的所有元素是按照它们在candidates[]中的索引大小顺序添加的,即:不能先添加后面的数,再添加前面的数。

我们使用 int used 来表示:当前组合cur[]中,已经使用到了第used个元素,所以之后为了不产生重复解,cur[]只能从candidates[used]开始添加。

dfs函数参数的含义:
cur : 当前试探的组合
sum: 当前组合的和
used: 当前组合cur[]中,已经使用到了第used个元素

优化:剪枝
先将candidates[]排序,若添加某个数后sum > target ,由于后面的数更大,一定也会使得 sum > target, 所以不用考虑,可以直接剪枝掉。

AC代码:

class Solution {
public:
    int n;
    void dfs(vector<int> cur, int sum, int used, vector<vector<int>>& ans,vector<int>& candidates,int target)
    {
        if(sum > target) return;
        if(sum == target)
        {
            ans.push_back(cur);
            return;
        }
        for(int i=used;i<n;i++)
        {
            vector<int> t = cur;
            t.push_back(candidates[i]);
            dfs(t,sum+candidates[i],i,ans,candidates,target);
            if(sum+candidates[i] > target) break;
        }
    }
    
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
        sort(candidates.begin(),candidates.end());
        vector<vector<int>> ans;
        vector<int> cur;
        n = candidates.size();
        dfs(cur,0,0,ans,candidates,target);
        return ans;
    }
};

猜你喜欢

转载自blog.csdn.net/STILLxjy/article/details/83627703