DFS-leetcode Combination Sum I/I I

深度优先搜索(DFS)是搜索算法的一种。最早接触DFS应该是在二叉树的遍历里面,二叉树的先序、中序和后序遍历实际上都属于深度优先遍历,实质就是深度优先搜索,后来在图的深度优先遍历中则看到了更纯正的深度优先搜索算法。

通常,我们将回溯法和DFS等同看待,可以用一个等式表示它们的关系:回溯法=DFS+剪枝。所以回溯法是DFS的延伸,其目的在于通过剪枝使得在深度优先搜索过程中如果满足了回溯条件不必找到叶子节点,就截断这一条路径,从而加速DFS。实际上,即使没有剪枝,DFS在从下层回退到上层的时候也是一个回溯的过程,通常这个时候某些变量的状态。DFS通常用递归的形式实现比较直观,也可以用非递归,但通常需要借组辅助的数据结构(比如栈)来存储搜索路径。

下面通过leetcode上的两个题目,来展示DFS的应用:

题一  Combination Sum I,题目大意是这样的:有一个正整数集合C,和一个目标数T(T也为正整数)。现从C中选出一些数,使其累加和恰好等于T(C中的每个数都可以取若干次),求所有不同的取数方案。

例如:C={2,3,6,7}  T=7

res={  [7],

[2, 2, 3] }

class Solution {
public:
    vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
        vector<int> tmp;
        sort(candidates.begin(),candidates.end()); //先对C中候选数升序排序,为后面的剪枝做准备
        sou=candidates;
        dfs(tmp,target,0);
        return res;
    }
private:
    vector<vector<int> > res;  //保存最后结果
    vector<int> sou;
    int sum(vector<int> tmp){ //计算累加和
        int r=0;
        for(int i=0;i!=tmp.size();++i)
            r+=tmp[i];
        return r;
    }
    void dfs(vector<int> &tmp,int tag,int l){
        if(l==sou.size()) //搜索到叶节点
            return ;
        int tot=sum(tmp);
        if(tot==tag){
            res.push_back(tmp);
            return ;
        }else if(tot>tag)  //剪枝
            return ;
        else{
            for(int i=l;i!=sou.size();++i){ //因为C中每个数可以选多次,所以i从l开始,而不是l+1
                tmp.push_back(sou[i]);
                dfs(tmp,tag,i);
                tmp.pop_back(); //回溯,恢复tmp状态
            }
        }
    }
};

题二  Combination Sum II,与题一得区别是集合C中的每个数最多只能取一次,不过C中可以有重复的数。

例如:C={10,1,2,7,6,1,5}  T=8

res={ [1, 7]

[1, 2, 5]

[2, 6]

[1, 1, 6] }

题二可以采用与题一类似的方法,但是由于题二中的每个数只能取一次,所以dfs函数中的for循环,i应从l+1开始,表示取下一个数。但这样带来的问题是,结果中会出现重复的取数方案,拿上面的例子来分析:C中有两个1可以选,那第一个1和7是一种可选方案(1+7=8),第二个1和7也是一种可选方案,按照上述算法,[1,7]会在结果中出现两次。当然可以对最后结果去重(如果用C++的话,sort->unique->erase可以实现)。不幸的是,这种解法会超时。解决超时的方案是不要将重复的方案加入到结果集中,也就避免了去重的工作。AC代码如下:

class Solution {
public:
    vector<vector<int> > combinationSum2(vector<int> &candidates, int target) {
        vector<int> tmp;
        for(int i=0;i!=candidates.size();++i){  //mm是一个map,key为C中可取的数,value为该数有多少个
            mm[candidates[i]]++;
        }
        for(map<int,int>::iterator it=mm.begin();it!=mm.end();++it){
            for(int i=0;i<it->second;++i){
                tmp.push_back(it->first);
                dfs(tmp,target,it);
            }
            for(int i=0;i<it->second;++i){  //回溯,恢复tmp状态
                tmp.pop_back();
            }
        }
        return res;
    }
private:
    vector<vector<int> > res; //保存最后结果
    map<int ,int > mm;

    int sum(vector<int> tmp){ //计算累加和
        int r=0;
        for(int i=0;i!=tmp.size();++i)
            r+=tmp[i];
        return r;
    }
    void dfs(vector<int> &tmp,int tag,map<int,int>::iterator it){
        if(it==mm.end())  //搜索到叶节点
            return ;
        int tot=sum(tmp);
        if(tot==tag){
            res.push_back(tmp);
            return ;
        }else if(tot>tag)  //剪枝
            return ;
        else{
            for(++it;it!=mm.end();++it){
                for(int i=0;i<it->second;++i){
                    tmp.push_back(it->first);
                    dfs(tmp,tag,it);
                }
                for(int i=0;i<it->second;++i){  //回溯,恢复tmp状态
                    tmp.pop_back();
                }
            }
        }
    }
};

关键代码:

for(++it;it!=mm.end();++it){
    for(int i=0;i<it->second;++i){
        tmp.push_back(it->first);
        dfs(tmp,tag,it);
    }
    for(int i=0;i<it->second;++i){  //回溯,恢复tmp状态
        tmp.pop_back();
    }
}

外层循环表示依次从C中选取一种数,内层的第一个循环表示C中这个数可以取几次,内层的第二个循环表示,如果不选上一个数的话,要恢复状态,即把保存的上一个数删除(加入了多少个,就删除多少个)。

DFS-leetcode Combination Sum I/I I

时间: 2024-10-12 17:26:46

DFS-leetcode Combination Sum I/I I的相关文章

[leetcode]Combination Sum @ Python

原题地址:https://oj.leetcode.com/problems/combination-sum/ 题意: Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited

LeetCode: Combination Sum [038]

[题目] Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. Note: All numbers (including target)

LeetCode: Combination Sum II [039]

[题目] Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. Each number in C may only be used once in the combination. Note: All numbers (including target) will be

Leetcode:Combination Sum 子集和问题

Combination Sum: Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. Note: All numbers (includ

Leetcode | Combination Sum I &amp;&amp; II

Combination Sum I Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The same repeated number may be chosen from C unlimited number of times. Note:All numbers (includ

LeetCode Combination Sum II (DFS)

题意: 在集合candidates中选出任意多个元素,使得他们的和为target,返回所有的组合,以升序排列. 思路: 难点在于如何去重,比如集合{1,1,2},target=3,那么只有一个组合就是1+2=3,而不是两个. DFS解决,每次考虑candidates[i]取还是不取,但是这样子还是会产生重复,这里只需要一个技巧就可以使得没有重复出现.如果当前元素已经被考虑过取了,那么在考虑不取的时候,i后面的与candidates[i]相同的都要跳过.观察一下可以发现,如果有一串相同的数字出现的

LeetCode: Combination Sum 解题报告

Combination Sum Combination Sum Total Accepted: 25850 Total Submissions: 96391 My Submissions Question Solution Given a set of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. The

LeetCode Combination Sum III

原题链接在这里:https://leetcode.com/problems/combination-sum-iii/ 与Combination Sum II相似,不同的是中不是所有元素相加,只是k个元素相加. 所以在把item的copy 加到res前需要同时满足item.size() == k 和 target == 0两个条件. AC Java: 1 public class Solution { 2 public List<List<Integer>> combinationS

LeetCode: Combination Sum II 解题报告

Combination Sum II Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T. Each number in C may only be used once in the combination. Note:All numbers (including ta

[LeetCode] Combination Sum III 组合之和之三

Find all possible combinations of k numbers that add up to a number n, given that only numbers from 1 to 9 can be used and each combination should be a unique set of numbers. Ensure that numbers within the set are sorted in ascending order. Example 1