# Combination Sum 系列问题（leetcode dfs回溯，动归）由浅入深DFS

Combination Sum问题 在leetcode的有一系列题目

39 Combination Sum（https://leetcode.com/problems/combination-sum/

# 39. Combination Sum

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.
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]
]

## 第一次, 按照普通的dfs，debug发现有重复的结果

class Solution {
private:
vector<vector<int>> ans;
vector<int> rs;
public:

void dfs(int nowSum, vector<int> cand, int candSize, int target)
{
if (nowSum > target)
return;
if (nowSum == target)
{
ans.push_back(rs);
return;
}
for (int i = 0; i < candSize; i++){
rs.push_back(cand[i]);
dfs(nowSum + cand[i], cand, candSize,target);
rs.pop_back();
}
}

vector<vector<int>> combinationSum(vector<int>& candidates, int target) {

int len = candidates.size();
if (len == 0)
return ans;

sort(candidates.begin(), candidates.end());// 排序

dfs(0, candidates,len, target);

return ans;
}
};

## 第二次，去除重复结果

//加一个nowIndex，每次只从当前到数组末尾，不选择比当前小的值，避免重复
class Solution {
private:
vector<vector<int>> ans;
vector<int> rs;
public:

void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target)
{
if (nowSum > target)
return;
if (nowSum == target)
{
ans.push_back(rs);
return;
}
for (int i = nowIndex; i < candSize; i++){
rs.push_back(cand[i]);
dfs(i,nowSum + cand[i], cand, candSize,target);
rs.pop_back();
}
}

vector<vector<int>> combinationSum(vector<int>& candidates, int target) {

int len = candidates.size();
if (len == 0)
return ans;

sort(candidates.begin(), candidates.end());// 排序

dfs(0,0, candidates,len, target);

return ans;
}
};

## ac，上面在计算结果 太耗时，因为有大量的没必要的计算

class Solution {
private:
vector<vector<int>> ans;
vector<int> rs;

public:

void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target)
{
if (nowSum > target)
return;
if (nowSum == target)
{
ans.push_back(rs);
return;
}
for (int i = nowIndex; i < candSize; i++){
if (nowSum + cand[i] <= target) // 因为cand是排序好的，显然会有大量的重复，应该避免，相当于剪枝
{
rs.push_back(cand[i]);
dfs(i, nowSum + cand[i], cand, candSize, target);
rs.pop_back();// 回溯
}
else
continue;
}
}

vector<vector<int>> combinationSum(vector<int>& candidates, int target) {

int len = candidates.size();
if (len == 0)
return ans;

sort(candidates.begin(), candidates.end());// 排序

dfs(0,0, candidates,len, target);

return ans;
}
};

# 40. Combination Sum II

## 有重复结果的代码1

class Solution {
public:

vector<int> candi;
int candiLen;
int tar;

vector<vector<int>> rs;
vector<int> ans;

void dfs(int curIndex, int curSum)
{

if(curSum == tar)
{
for(int i=0;i<(int)ans.size();i++)
cout << ans[i] << " ";
cout << endl;

rs.push_back(ans);
return;
}

if(curIndex >= candiLen || curSum > tar)
return;

for(int i = curIndex; i < candiLen; i++)
{
if(candi[i] > tar || candi[i] + curSum > tar)
break;

ans.push_back(candi[i]);

dfs(i + 1, curSum + candi[i]);

ans.pop_back();
}
}

vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
candi = candidates;
candiLen = candi.size();
if(candiLen > 1)
sort(candi.begin(), candi.end());
tar = target;

ans.clear();
rs.clear();

dfs(0,0);

return rs;
}
};

# 上面的去重条件加上 就可以ac了

class Solution {
public:

vector<int> candi;
int candiLen;
int tar;

vector<vector<int>> rs;
vector<int> ans;

void dfs(int curIndex, int curSum)
{
if(curSum == tar)
{
for(int i=0;i<(int)ans.size();i++)
cout << ans[i] << " ";
cout << endl;

rs.push_back(ans);
return;
}

if(curIndex >= candiLen || curSum > tar)
return;

for(int i = curIndex; i < candiLen; i++)
{
if(candi[i] > tar || candi[i] + curSum > tar)
break;

if(i > curIndex && candi[i] == candi[i-1]) // 去重
continue;

ans.push_back(candi[i]);

dfs(i + 1, curSum + candi[i]);

ans.pop_back();
}
}

vector<vector<int>> combinationSum2(vector<int>& candidates, int target)
{
candi = candidates;
candiLen = candi.size();
if(candiLen > 1)
sort(candi.begin(), candi.end());
tar = target;

ans.clear();
rs.clear();

dfs(0,0);

return rs;
}
};

if(curSum == tar)
{
for(int i=0;i<(int)ans.size();i++)
cout << ans[i] << " ";
cout << endl;

rs.push_back(ans);
return;
}

if(curIndex >= candiLen || curSum > tar)
return;

# ac2

class Solution {
private:
map<vector<int>, int> mp;
vector<vector<int>> ans;
vector<int> rs;
public:

void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target)
{
if (nowSum > target)
return;
if (nowSum == target)
{
// 因为仍然会有重复，利用map/set去重
if (mp[rs] == 0)
{
ans.push_back(rs);
mp[rs] = 1;
}
return;
}
// 从当前的下一个开始，不包括自己，因为每个数组中的数字
for (int i = nowIndex + 1; i < candSize; i++){
if (nowSum + cand[i] <= target) // 因为cand是排序好的，显然会有大量的重复，应该避免，相当于剪枝
{
rs.push_back(cand[i]);
dfs(i, nowSum + cand[i], cand, candSize, target);
rs.pop_back();// 回溯
}
else
continue;
}
}

vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {

int len = candidates.size();
if (len == 0)
return ans;

sort(candidates.begin(), candidates.end());// 排序

dfs(-1,0, candidates,len, target);

return ans;
}
};


# 216. Combination Sum III

ac代码

class Solution {
private:
vector<vector<int>> ans;
vector<int> rs;
public:

void dfs(int nowIndex,int nowSum, vector<int> cand, int candSize, int target,int nowRsSize,int k)
{
if (nowSum > target || nowRsSize > k)
return;
if (nowSum < target && nowRsSize == k)
return;
if (nowSum == target && nowRsSize == k)
{
ans.push_back(rs);
return;
}
// 从当前的下一个开始，不包括自己，因为每个数组中的数字
for (int i = nowIndex + 1; i < candSize; i++){
if (nowSum + cand[i] <= target && nowRsSize <= k) // 因为cand是排序好的，显然会有大量的重复，应该避免，相当于剪枝
{
rs.push_back(cand[i]);
dfs(i, nowSum + cand[i], cand, candSize, target,nowRsSize+1,k);
rs.pop_back();// 回溯
}
else
continue;
}
}

vector<vector<int>> combinationSum3(int k, int n) {

vector<int> candidates{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };

dfs(-1,0, candidates,9, n,0,k);

return ans;
}
};

# 77. Combinations

## 题目地址

https://leetcode.com/submissions/detail/78260609/

## 题目描述

Given two integers n and k, return all possible combinations of k numbers out of 1 … n.

For example,
If n = 4 and k = 2, a solution is:

[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]

## 求解

ac代码如下

class Solution {
private:
vector< vector<int> >ans;
vector<int> v;
public:
void dfs(int n, int k, int nowK, int indexN)
{
if (nowK > k)
return;
if (nowK == k)
{
/*for (int i = 0; i < k; i++)
cout << v[i] << " ";
cout << endl;*/
ans.push_back(v);
return;
}
for (int i = indexN; i <= n; i++)
{
v.push_back(i);
dfs(n, k, nowK + 1, i + 1);
v.pop_back();
}

}
vector<vector<int>> combine(int n, int k) {
dfs(n, k, 0, 1);
return ans;
}
};

# 377. Combination Sum IV

## 题目地址

https://leetcode.com/problems/combination-sum-iv/

## 题目描述

Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.

Example:

nums = [1, 2, 3]
target = 4

The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

Note that different sequences are counted as different combinations.

Therefore the output is 7.

What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?

## 求解

class Solution {
public:

int combinationSum4(vector<int>& nums, int target) {
int len = nums.size();

sort(nums.begin(), nums.end());
vector<int> dp(target + 1, 0); // dp[i] 表示 能组成 等于i的个数  dp[i - num] + num 可以凑成 dp[i]
dp[0] = 1;

for (int i = 1; i <= target; i++)
{
for (int j = 0; j < len; j++)
{
if (nums[j] <= i)
dp[i] += dp[i - nums[j]];
else
break;
}
}
return dp[target];
}
};