思路:回溯法+剪枝法(相当不错的题目,递归三部曲)
1.递归什么时候结束:当target为0时,递归结束;
2.每个递归的返回值是什么:每个递归结束后表示已经完成了后续的剪枝操作;
3.每级递归中要做的事:遍历选取当前要剪的那个枝,即把当前的所有的数字(枝)依次过一遍(依次压入、弹出)。
如输入: candidates = [2, 3, 5, 7],target = 7,所求解集为: [[2, 2, 3],[2,5], [7]]
为了防止出现结果重复的情况(如[2,5]和[5,2]其实是同一个结果),对原始数组先进行升序排序,这样就能保证当前剪枝的值>=上一次剪枝的值。
每次剪枝都会产生多个新的子递归
第一次写的代码如下,发现可以继续优化:
class Solution {
public:
vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
sort(candidates.begin(), candidates.end());//从小到大排序
combinationSumCore(candidates, 0, target);
return res;
}
private:
vector<vector<int>> res;
vector<int> path;
void combinationSumCore(vector<int> &candidates, int start, int target) {
if (target == 0)
{
res.push_back(path);
return; //子递归结束
}
for (int i = start; i < candidates.size(); i++)//核心
{
path.push_back(candidates[i]);
if(target - candidates[i] >= 0)
combinationSumCore(candidates, i, target - candidates[i]);
path.pop_back();//上一句总是会出来的
}
}
};
优化后的代码如下:
#include <iostream>
#include <vector>
#include<algorithm>
using namespace std;
//DFS
class Solution {
public:
vector<vector<int>> combinationSum(vector<int> &candidates, int target) {
sort(candidates.begin(), candidates.end());//从小到大排序
combinationSumCore(candidates, 0, target);
return res;
}
private:
vector<vector<int>> res;
vector<int> path;
void combinationSumCore(vector<int> &candidates, int start, int target) {
if (target == 0)//递归结束的条件
{
res.push_back(path);
return;
}
for (int i = start; i < candidates.size() && target - candidates[i] >= 0; i++)
{
path.push_back(candidates[i]);
combinationSumCore(candidates, i, target - candidates[i]);//已经完成了后续的剪枝操作
path.pop_back();
}
}
};