## 子集系列(二) 满足特定要求的子集，例 [LeetCode] Combination, Combination Sum I, II

### 例 1，求元素数量为定值的所有子集

Combinations

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],
]
class Solution {
public:
vector<vector<int> > combine(int n, int k) {
}
}

class Solution {
public:
vector<vector<int> > combine(int n, int k) {
if(n < k) return res;
combineCore(1, n, k);
return res;
}
private:
vector<int> path;
vector<vector<int> > res;
void combineCore(int st, int n, int k){
if(path.size() == k){
res.push_back(path);
return;
}
if(st > n) return;
combineCore(st+1, n, k); //case1: skip
path.push_back(st);
combineCore(st+1, n, k); //case2: not skip
path.pop_back();
}
};

AC 52ms。

class Solution {
public:
vector<vector<int> > combine(int n, int k) {
if(n < k) return res;
vector<int> v;
combineCore(1, n, k, v);
return res;
}
private:
vector<vector<int> > res;
void combineCore(int st, int n, int k, vector<int> &v){
if(k == 0){
res.push_back(v);
return;
}
for(int i = st; i <= n-k+1; ++i){
v.push_back(i);
combineCore(i+1, n, k-1, v);
v.pop_back();
}
}
};

AC 48ms。

### 例 2.1，求元素和为定值的所有子集

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.
• Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
• 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]

class Solution {
public:
vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
}
};

class Solution {
public:
vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
if(target <= 0) return res;
if(candidates.size() == 0) return res;
sort(candidates.begin(), candidates.end());    //排序
if(candidates.size() > 1){ //去重
int p = 0, q = 1;
while(q < candidates.size()){
if(candidates[p] != candidates[q]){
candidates[++p] = candidates[q++];
}else{
++q;
}
}
candidates.erase(candidates.begin()+p+1, candidates.end());
}
combinSumCore(candidates, 0, target);
return res;
}
private:
vector<int> path;
vector<vector<int> > res;
void combinSumCore(vector<int> &candidates, int st, int target) {
if(target == 0){
res.push_back(path);
return;
}
if(target < 0 || st >= candidates.size() || candidates[st] > target) return;
combinSumCore(candidates, st+1, target); //case1: skip
path.push_back(candidates[st]);
combinSumCore(candidates, st, target - candidates[st]); //case2: not skip，但是st这里不+1，因为数可以被用多次。
path.pop_back();
}
};

AC 60ms

### 例 2.2，求元素和为定值的所有子集

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.
• Elements in a combination (a1, a2, … , ak) must be in non-descending order. (ie, a1 ≤ a2 ≤ … ≤ ak).
• 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]

class Solution {
public:
vector<vector<int> > combinationSum2(vector<int> &num, int target) {}
};

class Solution {
public:
vector<vector<int> > combinationSum2(vector<int> &num, int target) {
if(num.size() == 0) return res;
sort(num.begin(), num.end());
combinationSumCore(num, 0, target);
return res;
}
private:
vector<int> path;
vector<vector<int> > res;
void combinationSumCore(vector<int> &num, int start, int target) {
if(target < 0) return;
if(target == 0){
vector<int> v;
res.push_back(path);
return;
}
if(start < num.size()){
int i = start+1;
for(; i < num.size() && num[start] == num[i]; ++i);
combinationSumCore(num, i, target);//case1: Jump 掉相同的

int sum = 0, j = i-1;
for(; j >= start; --j){
sum += num[j];
path.push_back(num[j]);
combinationSumCore(num, i, target - sum);//case2: 这段相同段上的所有使用情况。
}
for(j = i-1; j >= start; --j){
path.pop_back();
}
}
}
};

AC 96ms

class Solution {
public:
vector<vector<int> > combinationSum2(vector<int> &num, int target) {
if(target <= 0) return res;
sort(num.begin(), num.end());
combinationSumCore(0, num, target);
return res;
}

private:
vector<int> path;
vector<vector<int> > res;
void combinationSumCore(int st, vector<int> &num, int target)
{
if(target < 0) return;
if(st == num.size()){
if(target == 0)
res.push_back(path);
return;
}

//Handle target >= 0，下面的部分和Subset II思路二的代码一样。
if(path.size() == 0 || path[path.size()-1] != num[st])
combinationSumCore(st+1, num, target);
path.push_back(num[st]);
combinationSumCore(st+1, num, target-num[st]);
path.pop_back();
}
};

AC 102ms

### 结语

posted on 2014-08-31 06:33  Felix Fang  阅读(1187)  评论(0编辑  收藏  举报