【leetcode】40Combination Sum II(回溯方法)

来源:互联网 发布:latex mac版 编辑:程序博客网 时间:2024/04/29 16:38

题目大意:

给出一个候选数字集(其中可能有重复的数字),还有一个目标数字,数字均为正整数,从候选数字集中选取数字,候选集中每个元素最多选一次(若相同数字有多个则可多次选取),要求输出所有满足和为目标数的不重复的方案。

例子:候选集为[10, 1, 2, 7, 6, 1, 5],目标值为8

结果为

  [1, 7],
  [1, 2, 5],
  [2, 6],
  [1, 1, 6]


思路:
1.首先应对候选数字集进行排序,可使相同数字相邻,且方便后续剪枝
2.为了保证输出的方案不重复,应仔细考虑有重复数字的情况,这也是这道题的重点:
比较容易想出的方法是先对于重复的数字计数,再继续考虑选择0个至cnt个的情况,基于这种思想是下面的代码1
看了讨论区得到的另一种思路是,对于相同元素,每次都选择前面的
(例如有三个相同的数字,用1表示选择,0表示不选择,000,100,110,111代表了所有不重复的情况,则000,1xx已经包含所有情况。
代码2中先在tmp中加入了candidates[i],然后BackTracking(candidates,target-candidates[i],i+1,tmp,ans))即是1xx这种情况,
对于000这种情况,这份代码中没有显式调用BackTracking(candidates,target,i+1,tmp,ans)),而是跳过后序重复元素后进入下一次循环,新的一次循环中只有i的值改变了,其效果与显式调用相同

方法一:16ms
class Solution {public:    void combination(vector<int>&candidates,int target,int pos,vector<int>&tmp,vector<vector<int>>&ans)    {        if(target==0)        {            ans.push_back(tmp);            return;        }        int n=candidates.size();        if(pos>=n) return;        int x=candidates[pos];        int cnt=1;        while((pos+cnt<n)&&candidates[pos+cnt]==x) ++cnt;  //对重复的数字计数        int i;        for(i=0;i<=cnt;++i)     //针对选择0个至cnt个元素分别调用函数            {                if(i*x<=target)                {                    combination(candidates,target-i*x,pos+cnt,tmp,ans);                    tmp.push_back(x);                }                else break;            }        for(int j=1;j<=i;++j)            tmp.pop_back();     //回溯    }    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {        sort(candidates.begin(),candidates.end());        vector<vector<int>> ans;        vector<int>tmp;        combination(candidates,target,0,tmp,ans);        return ans;    }};



方法二:8ms
class Solution {public:    void BackTracking(vector<int>&candidates,int target,int pos,vector<int>&tmp,vector<vector<int>>&ans)    {        if(target==0)            ans.push_back(tmp);        else        {            int n=candidates.size();            for(int i=pos;i<n&&candidates[i]<=target;++i)            {                tmp.push_back(candidates[i]);                BackTracking(candidates,target-candidates[i],i+1,tmp,ans);    //选择了candidates[i]的情况                tmp.pop_back();                while(i+1<n&&candidates[i]==candidates[i+1]) ++i;   //选择了重复数字的情况已在上面包含,这里需要略去相同数字            }        }    }    vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {        sort(candidates.begin(),candidates.end());        vector<vector<int>> ans;        vector<int>tmp; //临时存储当前组合        BackTracking(candidates,target,0,tmp,ans);        return ans;    }};


0 0
原创粉丝点击