给定两个整数n
和k
,返回1 ... n
中所有可能的 k
个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
vector
容器和存储每个结点的一维vector
容器。二维容器用于将每次一维容器装满元素后的压入。而大小为k
的一维容器用于装大小为k
的个数的组合。当数量满足为k
的时候,压入到二维容器中。k
个时,需要结点回退,重新将下一个新的元素压入一维容器中。再加上for
循环,可以保证遍历到所有符合情况且不重复的元素。k
值问题,在遍历过程中,n
个结点剩余小于k
个结点没有遍历时,可以停止遍历,因为此时已不满足k
个元素成为一个新的结点压入到二维数组中。这是一种剪枝的思想。class Solution {
public:
vector< vector<int> > res; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
void backtracking(int startIndex, int n, int k) {
if (path.size() == k) {
res.push_back(path);
return;
}
// 这个for循环有讲究,组合的时候 要用startIndex,排列的时候就要从0开始
for (int i = startIndex; i <= n - (k - path.size()) + 1; i++) {
path.push_back(i); // 处理节点
backtracking(i + 1, n, k);
path.pop_back(); // 回溯,撤销处理的节点
}
}
vector<vector<int>> combine(int n, int k) {
backtracking(1, n, k);
return res;
}
};
class Solution {
public:
vector< vector<int> > ans;
vector<int> temp;
void deepFirstTraverse(int index, int n, int k){
if(temp.size() == k){
ans.push_back(temp);
return;
}
if(temp.size() + (n - index + 1) < k)
return;
temp.push_back(index);
deepFirstTraverse(index + 1, n, k);
temp.pop_back();
deepFirstTraverse(index + 1, n, k);
}
vector<vector<int>> combine(int n, int k) {
deepFirstTraverse(1, n, k);
return ans;
}
};
给定一个无重复元素的数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为target
的组合。
candidates
中的数字可以无限制重复被选取。
说明:
所有数字(包括 target)都是正整数。
解集不能包含重复的组合。
示例 1:
输入:candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2:
输入:candidates = [2,3,5], target = 8,
所求解集为:
[
[2,2,2,2],
[2,3,3],
[3,5]
]
提示:
1 <= candidates.length <= 30
1 <= candidates[i] <= 200
candidate 中的每个元素都是独一无二的。
1 <= target <= 500
class Solution {
public:
vector< vector<int> > ans;
vector<int> temp;
void DeepFirstTraverse(int index, vector<int>& candidates, int target){
int acc = accumulate(temp.begin(), temp.end(), 0);
if(acc == target){
ans.push_back(temp);
return;
}
for(int i = index; i < candidates.size(); i++){
if(target - acc >= candidates[i]){
// 剪枝
temp.push_back(candidates[i]);
DeepFirstTraverse(i, candidates, target);
temp.pop_back(); // 回溯
}
else
break;
}
}
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
DeepFirstTraverse(0, candidates, target);
return ans;
}
};
给定一个数组 candidates
和一个目标数 target
,找出 candidates
中所有可以使数字和为 target
的组合。
candidates
中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
[1,2,2],
[5]
]
class Solution {
public:
vector< vector<int> > ans;
vector<int> temp;
void dfs(int index, vector<int>& candidates, int target){
int acc = accumulate(temp.begin(), temp.end(), 0);
if(acc == target){
auto it=ans.begin();
it=find(ans.begin(),ans.end(),temp);
if(it==ans.end())
ans.push_back(temp);
}
for(int i = index; i < candidates.size(); i++){
if(target - acc >= candidates[i]){
temp.push_back(candidates[i]);
dfs(i + 1, candidates, target);
temp.pop_back();
}
else
break;
}
}
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
sort(candidates.begin(), candidates.end());
dfs(0, candidates, target);
//sort(ans.begin(), ans.end());
//vector< vector >::iterator iter;
//iter = unique(ans.begin(), ans.end());
//ans.erase(iter, ans.end());
return ans;
}
};
class Solution {
vector<int> nums;
vector<vector<int>> ans;
vector<int> a;
public:
vector<vector<int>> combinationSum2(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
this->nums = move(nums);
dfs(0, target);
return ans;
}
void dfs(int l, int target) {
if (target == 0) {
ans.push_back(a);
return;
}
for (int i = l; i < nums.size(); ++i) {
if (target - nums[i] < 0) break; //剪枝1
if (i > l && nums[i] == nums[i - 1]) continue; //剪枝2
a.push_back(nums[i]);
dfs(i + 1, target - nums[i]);
a.pop_back();
}
}
};
找出所有相加之和为 n
的 k
个数的组合。组合中只允许含有1 - 9
的正整数,并且每种组合中不存在重复的数字。
说明:
所有数字都是正整数。
解集不能包含重复的组合。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
0-9
的数组用过初始数组。定义二维容器和一维容器,判断条件就是以为容器元素和为n
并其长度为k
。class Solution {
public:
vector< vector<int> > ans;
vector<int> temp;
void dfs(int index, vector<int>& a, int k, int n){
int acc = accumulate(temp.begin(), temp.end(), 0);
if(n == acc and temp.size() == k){
ans.push_back(temp);
return;
}
for(int i = index; i < a.size(); i++){
if(n - acc >= 0 and temp.size() <= k){
temp.push_back(a[i]);
dfs(i + 1, a, k, n);
temp.pop_back();
}
else
break;
}
}
vector<vector<int>> combinationSum3(int k, int n) {
vector<int> a = {
1, 2, 3, 4, 5, 6, 7, 8, 9};
dfs(0, a, k, n);
return ans;
}
};
给定一个由正整数组成且不存在重复数字的数组,找出和为给定目标正整数的组合的个数。
示例:
nums = [1, 2, 3]
target = 4
所有可能的组合为:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)
请注意,顺序不同的序列被视作不同的组合。
因此输出为 7。
进阶:
如果给定的数组中含有负数会怎么样?
问题会产生什么变化?
我们需要在题目中添加什么限制来允许负数的出现?
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
vector<unsigned long long> dp(target + 1, 0);
dp[0] = 1;
for(int i = 0; i <= target; i++){
for(int j = 0; j < nums.size(); j++){
if(i - nums[j] >= 0)
dp[i] += dp[i - nums[j]];
}
}
return dp[target];
}
};