Leetcode Combination Sum I,II,III 均是dfs + backtraing 模板题目,适合集中练习
Leetcode - 039. Combination Sum
我的思路:
1.排序是必要的,为什么排序是必要的?考虑到我们dfs + backtraing 的标准三步(1.优先判定可行解 2.剪枝 3.遍历下行状态,更新backtracing的追踪变量),我们如何判定是一个可行解,显然是当前sum = target,那么如果我们不排序的话当前sum > target 还有可能pop 最后一个元素然后与之后较小的元素形成可行解,这样带来了不必要的麻烦而且无法剪枝,所以我们应该排序原数组
2.遵循标准三步,注意是可重复的peek,那么每次的下行状态包括当前状态的终止位置
class Solution {
public:
void dfs(vector> &vct, vector &cur, vector& nums,
const int target, int cursum, int index)
{
if (cursum == target)
{
vct.push_back(cur);
return;
}
int n = nums.size();
if (cursum > target || index >= n)
return;
for (int i = index; i < n; ++i)
{
cur.push_back(nums[i]);
dfs(vct, cur, nums, target, cursum + nums[i], i);
cur.pop_back();
}
}
vector> combinationSum(vector& candidates, int target) {
vector> vct;
vector cur;
if (candidates.size() <= 0)
return vct;
sort(candidates.begin(), candidates.end());
dfs(vct, cur, candidates, target, 0, 0);
return vct;
}
};
Leetcode - 040. Combination Sum II
我的思路:
1.主体思路与Combination Sum 是一致的
2.有重复元素
3.元素只能使用一次
这里的去重操作需要技巧:
首先,每个元素(不管是否与其他元素相等)只能使用一次,可以用used数组标识
考虑到样例中给出的 1 + 1 + 6 = 8,不能单纯的后置元素等于前置元素去重,那我们考虑什么时候重复?
假设样本[1,1,1,3] , target = 5, 那么解为[1,1,3]
根据深搜的性质,一定是index = 0,1,3的元素组成了解,那么我们可以了解到的是,当元素存在前置等值元素且其前置等值元素还未被使用时就使用当前元素必然会发生重复解。了解这一点,稍作判断修改即可AC
class Solution {
public:
void dfs(vector> &vct, vector cur, vector& nums, vector& used,
const int target, int cursum, int index)
{
if (cursum == target)
{
vct.push_back(cur);
return;
}
int n = nums.size();
if (cursum > target || index >= n)
return;
for (int i = index + 1; i < n; ++i)
{
int j = i - 1;
int placable = 1;
while (j >= 0 && nums[j] == nums[i])
{
if (used[i] == 0)
{
placable = 0;
break;
}
}
if (placable == 0)
continue;
used[i] = 1;
cur.push_back(nums[i]);
dfs(vct, cur, nums, used, target, cursum + nums[i], i + 1);
cur.pop_back();
used[i] = 0;
}
}
vector> combinationSum2(vector& candidates, int target) {
vector> vct;
vector cur;
int n = candidates.size();
if (n <= 0)
return vct;
vector used(n, 0);
sort(candidates.begin(), candidates.end());
dfs(vct, cur, candidates, used,target, 0, 0);
return vct;
}
};
Leetcode - 216. Combination Sum III
我的思路:
1.使用k个1 - 9之间的正整数组成target,主体思路同上
2.剪枝的时候多加一个当前解空间的大小判断一下即可,论起来比起Combination Sum II还要容易一些
class Solution {
public:
void dfs(vector> &vct, vector &cur, vector &nums,
int k, int n, int index, int cursum)
{
if (int(cur.size()) == k && cursum == n)
{
vct.push_back(cur);
return;
}
// 注意这里可以取等和不能取等的
if (int(cur.size()) >= k || cursum >= n || index > 9)
return;
for (int i = index; i <= 9; ++i)
{
cur.push_back(i);
dfs(vct, cur, nums, k, n, i + 1, cursum + i);
cur.pop_back();
}
}
vector> combinationSum3(int k, int n) {
vector> vct;
vector cur;
vector nums{ 0,1,2,3,4,5,6,7,8,9 };
dfs(vct, cur, nums, k, n, 1, 0);
return vct;
}
};