如果还记的话或者写过LeetCode的人会知道,这是nsum,已经不再是之前的twosum,threesum,foursum了。之前是都是使用 i 层循环解题的,那么现在n层循环理论上是可以解题的(其实应该不行),但是n是不确定了,而且是可变的,其变化范围是[1,n]
说道这里其实想说明的是,我们要换种思路去解题了。我在看到这个题的时候想到的思路是:
我们从小到大一个一个将最小的数字重复不断的加入到 vector 中,若vector现有的值的和比 target 大则将 vector 集合中的元素减少一个,加入后面的元素继续比较,用到的还是回溯的方法。像这样递归加回溯最后肯定是可以求出所有的解的,其实这里还需要注意一点,就是判断vector中元素的和与target的大小关系时,我们不要直接将vector中所有元素的和求出来,而是利用一种巧妙的方法,将 ' target - val ' 作为 target 的更新值传递给循环(其中val指的是加入到vector中的值),最后target肯定会被减小到0的,此时真是我们要找到的值,将它加入到最终结果中。千万注意target不能以引用传递
上面的讲解可能会让你看的有些不懂,但是希望下面的代码能够帮助你理解,其实一旦思路明确后你就能解题了,代码如下:
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target)
{
/*
看到这个题的第一眼开始,我就想到了这个题和前面讲到的twosum,threesum,foursum不同,这个题目可能是 nsum, 所以n层循环的
做法不可取,我想到了是否可以回溯:不断加入元素,去测试,若元素的和与target相等则满足题意,若大于target则推出循环,若小于则
可以继续测试。
*/
vector<vector<int>> ret;
ret.clear();
vector<int> tmp;
tmp.clear();
//题目并没有说明candidates是有序的,但是题目要求的结果是不能出现重复的集合,那么我们需要对candidates排序
sort(candidates.begin(),candidates.end());
//还是采用递归加上回溯法进行求解
_findAllSolve(candidates,ret,tmp,target,0);
return ret;
}
void _findAllSolve(vector<int>& candidates, vector<vector<int>>& ret,vector<int>& tmp,int target, int index)
{
if(target == 0)
{//此时说明tmp中的集合满足题意,加入到ret中
ret.push_back(tmp);
return ;
}
else
{
for(int i = index; i < candidates.size(); ++i)
{
if(candidates[i] > target)
{//题目中有说明candidates中元素都是非负的,而且candidates被排序过,此时可直接退出
return ;
}
//target > candidates[i] 那么我们就将candidates[i]加入到tmp中
tmp.push_back(candidates[i]);
_findAllSolve(candidates,ret,tmp,target-candidates[i],i);
//完成上面的过程后需要及时将它们移除,再看看还有其他的解没有
tmp.pop_back();
}
}
}
};
程序的结果如下: