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 (a1, a2, … , 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; } };