【问题描述】
Given a set of candidate numbers (C) (without duplicates) 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] ]问题来源:Combination Sum
【解题分析】
给出一个数据集和一个目标数字,找出数据集中所有满足和为目标数字的子集合,数据集中的数字可重复使用,但最后满足条件的集合不得重复。
采用深度优先算法DFS:
就以题中的例子讲解一下算法,2->2->2->2,发现8>7,遍历上一节点的其他子节点,2->2->2->3,9>7,.....,直到2->2->2->7,返回到上一节点,开始2->2->3,......,如此,最后到6->6,6->7,7。
【源代码】
class Solution {
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<vector<int>> result;
vector<int> mid_result;
DFS(result, mid_result, candidates, 0, 0, target);
return result;
}
private:
void DFS(vector<vector<int>>& result, vector<int>& mid_result, vector<int> candidates, int i, int sum, int target) {
if (sum == target) {
result.push_back(mid_result);
return ;
} else if (sum > target){
return ;
} else {
for (int j = i; j < candidates.size(); j++) {
mid_result.push_back(candidates[j]);
DFS(result, mid_result, candidates, j, sum + candidates[j], target);
mid_result.pop_back(); /*该节点已被遍历,且该节点已无子节点需要遍历,将其取出*/
}
}
}
};
Combination Sum II
【问题描述】
Given a collection of candidate numbers (C) and a target number (T), find all unique combinations in C where the candidate numbers sums to T.
Each number in C may only be used once in the combination.
Note:
- All numbers (including target) will be positive integers.
- The solution set must not contain duplicate combinations.
For example, given candidate set [10, 1, 2, 7, 6, 1, 5]
and target 8
,
A solution set is:
[ [1, 7], [1, 2, 5], [2, 6], [1, 1, 6] ]问题来源:Combination Sum II
【解题分析】
这题和上面那题非常相似,只不过多加了条件,那就是集合内的元素不得重复使用,而且有个不同于前一题的条件,那就是集合内的元素可能会重复。
基于以上的条件,我们仍采用上一题的思路,只不过这次我们不会连续重复遍历一个节点。
for (int i = start; i < candidates.size(); i++) {
mid_result.push_back(candidates[i]);
DFS(candidates, i + 1, sum + candidates[i], target, mid_result, result);
mid_result.pop_back();
}
区别于上一题:
for (int j = i; j < candidates.size(); j++) {
mid_result.push_back(candidates[j]);
DFS(result, mid_result, candidates, j, sum + candidates[j], target);
mid_result.pop_back(); /*该节点已被遍历,且该节点已无子节点需要遍历,将其取出*/
}
而且由于集合内的元素可能会重复,那么得到的结果集合内可能会有相同的集合。我们需要去掉重复集合。
sort(result.begin(), result.end());
result.erase(unique(result.begin(), result.end()), result.end());
【源代码】
class Solution {
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<vector<int>> result;
vector<int> mid_result;
int sum = 0;
sort(candidates.begin(), candidates.end());
DFS(candidates, 0, 0, target, mid_result, result);
sort(result.begin(), result.end());
result.erase(unique(result.begin(), result.end()), result.end());
return result;
}
private:
void DFS(vector<int> candidates, int start, int sum, int target, vector<int>& mid_result, vector<vector<int>>& result) {
if (sum == target) {
result.push_back(mid_result);
} else if (sum > target) {
return ;
} else {
for (int i = start; i < candidates.size(); i++) {
mid_result.push_back(candidates[i]);
DFS(candidates, i + 1, sum + candidates[i], target, mid_result, result);
mid_result.pop_back();
}
}
}
};