回溯算法:组合问题I,II,III
组合问题
回溯+剪枝代码如下:
剪枝过程:i + (k - path.size()) <= n + 1
,数组为单调递增的,当前位置不成立后,后序数字也无需进行比较了
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combine(int n, int k) {
int step = 0;
int start = 1;
backtrack(n, k, start, step);
return res;
}
void backtrack(int n, int k, int start, int step)
{
//退出条件
if(step == k)
{
res.push_back(path);
return;
}
//单层节点的操作
for(int i = start; i + (k - path.size()) <= n + 1; i++)
{
step++;
path.push_back(i);
//递归
backtrack(n, k, i + 1, step);
//回溯
step--;
path.pop_back();
}
}
};
组合总和问题
思路:回溯+剪枝
剪枝过程:i < candidates.size() && sum + candidates[i] <= target
在for循环内进行控制,注意,剪枝的话需要将数组进行从小到大排序,具体原因说明见代码:
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
int sum = 0;
//需要排序candidates =【2,7,6,3,5,1】,target =【9】
//假如第+candidates【0】>target,但是+candidates【5】=target
//那么不排序的话for循环直接终止,后面的也就无法比较了
sort(candidates.begin(), candidates.end());
backtrack(candidates, target, sum, 0);
return res;
}
void backtrack(vector<int>& candidates, int target, int sum, int startIndex)
{
if(sum == target)
{
res.push_back(path);
return;
}
if(sum > target)
{
return;
}
for(int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++)
{
path.push_back(candidates[i]);
sum += candidates[i];
//递归
backtrack(candidates, target, sum, i);
//回溯
path.pop_back();
sum -= candidates[i];
}
}
};
组合总和问题II
思路:与之前不同的是需要去重
condidates:【1,1,2, 5,6,7,10】 target = 8
第一想法是去重嘛,这还不简单,啪的一声很快啊!写出来candidates[i] == candidates[i-1]
这样出大问题,你控制的不是同一层的重复元素,简单点说【1,1,6】这种情况就直接没有了,因此正确的去重:i > startIndex && candidates[i] == candidates[i-1]
代码:
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
//排序
sort(candidates.begin(), candidates.end());
int sum = 0;
vector<bool> use(candidates.size(), false);
backtrack(candidates, target, sum, 0, use);
return res;
}
void backtrack(vector<int>& candidates, int target, int sum, int startIndex, vector<bool>& use)
{
if(sum == target)
{
res.push_back(path);
return;
}
for(int i = startIndex; i < candidates.size() && sum + candidates[i] <= target; i++)
{
//对同一层相同元素进行跳过
if(i > startIndex && candidates[i] == candidates[i-1])
continue;
path.push_back(candidates[i]);
sum += candidates[i];
//递归
backtrack(candidates, target, sum, i + 1, use);
//回溯
path.pop_back();
sum -= candidates[i];
}
}
};
组合总和问题 III
思路:和组合总和I大同小异
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combinationSum3(int k, int n) {
int startIndex = 1;
int sum = 0;
backtrack(k, n, startIndex, sum);
return res;
}
void backtrack(int k, int n, int startIndex, int sum)
{
//退出条件
if(path.size() == k)
{
if(sum == n)
{
res.push_back(path);
}
return;
}
//单层节点处理
for(int i = startIndex; i <= 9; i++)
{
path.push_back(i);
sum += i;
//递归
backtrack(k, n, i + 1, sum);
//回溯
sum -= i;
path.pop_back();
}
}
};