Combination Sum

来源:互联网 发布:淘宝如何设置图片保护 编辑:程序博客网 时间:2024/05/22 10:09

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) will be positive integers.
  • Elements in a combination (a1a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
  • The solution set must not contain duplicate combinations.

For example, given candidate set 2,3,6,7 and target 7
A solution set is: 
[7] 

[2, 2, 3] 

题目分析:

给定一个集合C,求集合C中元素相加为target的子集的集合,C的元素可重复,最终所求子集集合中元素(子集)不能重复。

方法一:

相当于一棵树,我们对它进行深度遍历,找到最终路径和为target的路径即可。代码如下:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {         vector<vector<int>> res;        if(candidates.size()==0) return res;        if(target<=0) return res;        int len=candidates.size();        sort(candidates.begin(),candidates.end());stack<vector<int>> st;for(int i=candidates.size()-1;i>=0;i--){vector<int>temp;temp.push_back(candidates[i]);if(accumulate(temp.begin() , temp.end() , 0)==target)res.push_back(temp);else if(accumulate(temp.begin() , temp.end() , 0)<target)st.push(temp);else;}while(!st.empty())//用迭代的方法深度遍历,用栈实现,栈内元素为路径各节点值。{vector<int> node=st.top();st.pop();int pre=accumulate(node.begin() , node.end() , 0);for(int i=candidates.size()-1;i>=0;i--)   {vector<int> temp=node;temp.push_back(candidates[i]);if(accumulate(temp.begin() , temp.end() , 0)==target){sort(temp.begin(),temp.end());int flag=0;for(int j=0;j<res.size();j++)//判断res中是否已经加入该路径{if(res[j].size()==temp.size()){int t;for(t=0;t<temp.size();t++)        {if(res[j][t]!=temp[t]){break;}}if(t==temp.size()){flag=1;//已有相同的并加入到了res}}}if(flag==0)res.push_back(temp);}else if(accumulate(temp.begin() , temp.end() , 0)<target)st.push(temp);else;   }}return res;            }
方法一优点:简单直观,缺点:代码略长,并且在leetcode中会判断超时,但是在VS下运行超时的用例可以得到结果且正确。

方法二:

我们将回溯法和DFS(深度遍历)同等看待,可以用一个等式表示它们的关系:回溯法=DFS+剪枝。所以回溯法是DFS的延伸,其目的在于通过剪枝使得在深度优先搜索过程中如果满足了回溯条件不必找到叶子节点,就截断这一条路径,从而加速DFS。实际上,即使没有剪枝,DFS在从下层回退到上层的时候也是一个回溯的过程,通常这个时候某些变量的状态。DFS通常用递归的形式实现比较直观,也可以用非递归,但通常需要借组辅助的数据结构(比如栈)来存储搜索路径。思想如此,代码如下:
<pre name="code" class="cpp">class Solution {public:vector<vector<int>> res; vector<int> pre; void cm(vector<int>& p, int tag,int l) { if(l==pre.size()) return; int temp=accumulate(p.begin() , p.end() , 0); if(temp==tag) { res.push_back(p); return ; } else if(temp>tag) return; else { for(int i=l;i!=pre.size();i++)//因为candidates的元素可以重复使用,所以i=l { p.push_back(pre[i]); cm(p,tag,i); p.pop_back(); } } }    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {        if(candidates.size()==0) return res;         if(target<=0) return res;         int len=candidates.size(); sort(candidates.begin(),candidates.end()); pre=candidates; vector<int> tmp;//tmp为所要求的子集 cm(tmp,target,0); return res;    }};
0 0