给出两个整数n和k,返回从1到n中取k个数字的所有可能的组合
例如:
如果n=4,k=2,结果为
[ [2,4], [3,4], [2,3], [1,2], [1,3], [1,4], ]
//清晰简单的C++代码, DFS
class Solution {
public:
void DFS(vector<vector<int>> &ret, vector<int> &path, int n, int start, int rest){
if(!rest)
ret.push_back(path);
else{
for(int i=start; i<=n-rest+1; ++i){
path.push_back(i);
DFS(ret, path, n, i+1, rest-1);
path.pop_back();
}
}
}
vector<vector<int> > combine(int n, int k) {
vector<vector<int>> ret;
vector<int> path;
DFS(ret, path, n, 1, k);
return ret;
}
};
class Solution {
public:
vector<vector<int> > combine(int n, int k) {
vector<vector<int> > res;
vector<int> ans;
build(1,k,n,res,ans);
return res;
}
private:
void build(int num,int k,int n,vector<vector<int> > &res,vector<int> &ans){
if(k==0){
res.push_back(ans);
return;
}
if(num>n)return;
//将该元素num放入组合集中,然后在剩下的n-1个数中再选择m-1个元素
ans.push_back(num);
build(num+1,k-1,n,res,ans);
ans.pop_back();
//不选择该元素,而从剩下的n-1个元素中选择m个元素
build(num+1,k,n,res,ans);
}
};
import java.util.ArrayList;
//使用剪枝对算法进行了优化;
//Your runtime beats 99.50 % of java submissions
public class Solution {
private ArrayList<ArrayList<Integer>> res;
public ArrayList<ArrayList<Integer>> combine(int n, int k) {
res = new ArrayList<ArrayList<Integer>>();
if (n <= 0 || k <= 0 || n < k)
return res;
generateCombinations(n, k, 1, new ArrayList<Integer>());
return res;
}
private void generateCombinations(int n, int k, int start, List<Integer> list) {
if (list.size() == k) {
res.add(new ArrayList<Integer>(list));
return;
}
if (start > n)
return;
int len = k - (list.size() + 1);
//list当中最终应该有k个元素,当前元素为list.size() + 1,那么我们要为下次回溯留下足够多的数
for (int i = start; i <= n - len; i++) {
list.add(i);
generateCombinations(n, k, i + 1, list);
list.remove(list.size() - 1);
}
}
}
class Solution {
public:
vector<vector<int> > combine(int n, int k) {
vector<vector<int>> dp[k];
for(int i = 1; i <= n - k + 1; i ++) {
vector<int> v;
v.push_back(i);
dp[0].push_back(v);
}
for(int i = 1; i < k; i ++){
for(auto it = dp[i-1].begin(); it != dp[i-1].end(); it++){
vector<int> v = *it;
for(int j = v.back() + 1; j <= n - k + i + 1; j++){
v.push_back(j);
dp[i].push_back(v);
v.pop_back();
}
}
}
return dp[k-1];
}
};
//没用递归整的 class Solution {
public:
vector<vector<int> > combine(int n, int k) {
vector<vector<int> > result;
vector<int> v;
Solve(1,n,k,result,v);
return result;
}
void Solve(int x,int n,int k,vector<vector<int> > &result,vector<int> &v)
{
if(k==0)
{
result.push_back(v);
return;
}
if(x > n)
return;
v.push_back(x);
Solve(x+1,n,k-1,result,v);
v.pop_back();
Solve(x+1,n,k,result,v);
}
}; //这个题目与“和为定值的多个数”非常相似,可以用同一种思路求解,所以做一个简单
//归纳,如果再遇见相似题目会继续加入进来。
#include <iostream>
#include <vector>
using namespace std;
void combinations(vector<int> arr, vector<int> &tempArr, int k, vector<vector<int>> &result){
if (tempArr.size() == k){
result.push_back(tempArr);
return;
}
if (arr.size() == 0)
return;
vector<int> newArr;
for (int i = 1; i < arr.size(); i++)
newArr.push_back(arr[i]);
//如果包含当前数字,只需要从剩余数字中搜索k-1个数字
tempArr.push_back(arr[0]);
combinations(newArr, tempArr, k, result);
//如果不包含当前数字,则从剩余数字中搜索k个数字
tempArr.pop_back();
combinations(newArr, tempArr, k, result);
}
int main(){
int n;
while (cin >> n){
vector<int> arr;
for (int i = 1; i <= n; i++)
arr.push_back(i);
int k = 0;
cin >> k;
vector<vector<int>> result;
vector<int> tempArr;
combinations(arr, tempArr, k, result);
for (int i = 0; i < result.size(); i++){
for (int j = 0; j < result[i].size(); j++){
cout << result[i][j] << " ";
}
cout << endl;
}
}
return 0;
}
//如果是求和为定值的多个数,数组元素不许重复,
//也即LeetCode的combination-sum2那道题。 //只需要对程序稍作改动:
class Solution {
public:
void search(vector<int> arr, int sum, vector<int> &tempArr, vector<vector<int>> &result){
if (sum == 0){
bool flag = false;
//这里是为了去除重复组合
for(int i = 0;i < result.size();i++){
if(tempArr == result[i]){
flag = true;
break;
}
}
if(!flag)
result.push_back(tempArr);
return;
}
if (arr.size() == 0)
return;
//这里是由于先对arr进行了升序排序,如果最小值大于sum,不必继续搜索
if (arr[0] > sum)
return;
tempArr.push_back(arr[0]);
vector<int> arr1;
for (int i = 1; i < arr.size(); i++)
arr1.push_back(arr[i]);
//如果包含当前数字,则只需要从剩余数字中搜索sum-arr[0],允许数字重复
search(arr1, sum - arr[0], tempArr, result);
//如果不包含当前数字,那么需要从剩余数字中索索sum
tempArr.pop_back();
search(arr1, sum, tempArr, result);
}
vector<vector<int> > combinationSum2(vector<int> &candidates, int target) {
vector<int> tempArr;
vector<vector<int>> result;
sort(candidates.begin(), candidates.end());
search(candidates, target, tempArr, result);
return result;
}
};
//依然是求和为定值的多个数,但是现在允许给定数组中的元素出现多次,依然可以用
//同样的套路计算,这实际上就是LeetCode中combination-sum那道题。
class Solution {
public:
void search(vector<int> arr, int sum, vector<int> &tempArr, vector<vector<int>> &result){
if (sum == 0){
result.push_back(tempArr);
return;
}
if (arr.size() == 0)
return;
//这里是由于先对arr进行了升序排序,如果最小值大于sum,不必继续搜索
if (arr[0] > sum)
return;
tempArr.push_back(arr[0]);
vector<int> arr1;
for (int i = 1; i < arr.size(); i++)
arr1.push_back(arr[i]);
//如果包含当前数字,则只需要从剩余数字中搜索sum-arr[0],允许数字重复
search(arr, sum - arr[0], tempArr, result);
//如果不包含当前数字,那么需要从剩余数字中索索sum
tempArr.pop_back();
search(arr1, sum, tempArr, result);
}
vector<vector<int> > combinationSum(vector<int> &candidates, int target) {
vector<int> tempArr;
vector<vector<int>> result;
sort(candidates.begin(), candidates.end());
search(candidates, target, tempArr, result);
return result;
}
}; classSolution {
public:
vector<vector<int> > vec; // 要返回的 vector
voidfun(vector<int> &vv,intii,intn,intk,intmx){
//用于递归的 函数 n 当前层数 k 最大层数
if(n == k){ //递归 到 结尾处 时 将 vv 添加到 vec 中
vec.push_back(vv);
return;
}
for(inti=ii+1;i<mx;i++){ //这一层 从 ii+1 开始 到 mx 结束
vv[n] = i;
fun(vv,i,n+1,k,mx+1); // 下一层 从 i 开始 到 mx+1 处结束
}
}
vector<vector<int> > combine(intn, intk) {
vector<int> vv(k);
vec.clear();
for(inti=1;i<n-k+2;i++){
vv[0] = i;
fun(vv,i,1,k,n-k+2+1);
}
returnvec;
}
};
class Solution {
public:
vector<vector<int>> a;
vector<vector<int> > combine(int n, int k) {
vector<int> b;
dfs(k,n,1,b);
return a;
}
void dfs(int k,int n,int start,vector<int>& y) {
if(y.size()==k) {
a.push_back(y);
return ;
}
for(int i=start;i<=n-(k-y.size())+1;i++) { //i的位置必须考虑集合中已有多少个元素,还差多少个元素,差(k-y.size())个,I的位置就必须小于等于n-(k-y.size())+1
y.push_back(i);
dfs(k,n,i+1,y);
y.pop_back();
}
}
};
//dfs爆搜所有结果
class Solution {
public:
vector<vector<int> > combine(int n, int k) {
vector<vector<int> >ans;
if(n<k) return ans;
vector<int>vec;
for(int i=1;i<=n-k+1;++i)
{
vec.push_back(i);
dfs(ans,vec,i,n,k,1);
vec.pop_back();
}
return ans;
}
private:
void dfs(vector<vector<int> >&res,vector<int>sub,int index,int n,int k,int cnt)
{
if(cnt>=k){
res.push_back(sub);
return ;
}
for(int i=index+1;i<=n;++i)
{
sub.push_back(i);
dfs(res,sub,i,n,k,cnt+1);
sub.pop_back();
}
return ;
}
};
public class Solution {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
public ArrayList<ArrayList<Integer>> combine(int n, int k) {
getAllCombineList(1, n, k, new ArrayList<>());
return res;
}
public void getAllCombineList(int start, int n, int k, ArrayList<Integer> list) {
if(k == 0) {
res.add(new ArrayList<>(list)); // 如果仅仅add(list)那么list.remove后,这个res也会减少
return;
}
for (int i = start; i <= n; i++) {
list.add(i);
getAllCombineList(i + 1, n, k - 1, list);
list.remove(list.size() - 1);
}
}
}
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer>> combine(int n, int k) {
ArrayList<ArrayList<Integer>> res = combineCore(n,k);
//排序
Collections.sort(res, (ArrayList<Integer> a,ArrayList<Integer> b)->{
for(int i=0;i<a.size() && i<b.size();i++){
if(a.get(i)!=b.get(i)){
return a.get(i).compareTo(b.get(i));
}
}
return new Integer(a.size()).compareTo(b.size());
});
return res;
}
private ArrayList<ArrayList<Integer>> combineCore(int n, int k){
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if(k>n || k==0){
return res;
}
if(k==1){
for(int i=1;i<=n;i++){
ArrayList<Integer> resList = new ArrayList<>();
resList.add(i);
res.add(resList);
}
return res;
}
//n在组合内
ArrayList<ArrayList<Integer>> nextRes1 = combineCore(n-1,k-1);
for(ArrayList<Integer> nextResList : nextRes1){
nextResList.add(n);
res.add(nextResList);
}
//n不在组合内
ArrayList<ArrayList<Integer>> nextRes2 = combineCore(n-1,k);
res.addAll(nextRes2);
return res;
}
}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public ArrayList<ArrayList<Integer>> combine(int n, int k) {
ArrayList<ArrayList<Integer>> resultList = new ArrayList<>();
getAllCombineList(1, n, k, resultList, new ArrayList<>());
return resultList;
}
public void getAllCombineList(int start, int n, int k,
ArrayList<ArrayList<Integer>> resultList,
ArrayList<Integer> list) {
if (k == 0) {
resultList.add(new ArrayList<>(list));
return;
}
for (int i = start; i <= n; i++) {
list.add(i);
getAllCombineList(i + 1, n, k - 1, resultList, list);
list.remove(list.size() - 1);
}
}
}
class Solution {
public:
vector<vector<int> > combine(int n, int k)
{
vector<vector<int>> res;
vector<int> combine;
dfs(n,k,1,res,combine);
return res;
}
void dfs(int n,int k,int start,vector<vector<int>> &res,vector<int> &combine)
{
if(combine.size() == k)
{
res.push_back(combine);
return;
}
for(int i=start;i<=n;i++)
{
combine.push_back(i);
dfs(n,k,i+1,res,combine);
combine.pop_back();
}
}
};
class Solution(object): def combine(self, n, k): if k == 0: return [] elif k == 1: return [[i] for i in range(1, n + 1)] elif n == k: return [[i for i in range(1, n + 1)]] else: return self.combine(n - 1, k) + map(lambda x: x + [n], self.combine(n - 1, k - 1))
// 朴素回溯,每次都递归地从当前选中元素后面的元素中选
class Solution {
public:
vector<vector<int>> res;
void backTrace(vector<int>& temp, int n, int k, int index) {
if (temp.size() == k) {
res.push_back(temp);
return;
}
for (int i = index; i <= n; i++) {
temp.push_back(i);
backTrace(temp, n, k, i + 1);
temp.pop_back();
}
}
vector<vector<int>> combine(int n, int k) {
vector<int> temp;
backTrace(temp, n, k, 1);
return res;
}
};
## 二叉树思路,yes or no,是否添加当前index数据 ## 递归添加当前路径 def binaryTreeSeq(nums,k,index,path,ans): if len(path)==k: ans.append(path) return if index==len(nums):return no=path binaryTreeSeq(nums,k,index+1,no,ans) yes=path+[nums[index]] binaryTreeSeq(nums,k,index+1,yes,ans) class Solution: def combine(self , n , k ): nums = list(range(1, n+1)) ans=[] binaryTreeSeq(nums,k,0,[],ans) ans=ans[::-1] return(ans) # write code here
回溯:
//
// Created by jt on 2020/9/24.
//
#include <vector>
using namespace std;
class Solution {
public:
/**
*
* @param n int整型
* @param k int整型
* @return int整型vector<vector<>>
*/
vector<vector<int> > combine(int n, int k) {
// write code here
vector<vector<int>> res;
vector<int> vec;
backtrack(res, vec, n, k);
return res;
}
void backtrack(vector<vector<int>> &res, vector<int> &vec,
int n, int k) {
if (vec.size() == k) { res.push_back(vec); return; }
int start = vec.empty() ? 1 : vec[vec.size() - 1] + 1;
for (int i = start; i <= n; ++i) {
vec.push_back(i);
backtrack(res, vec, n, k);
vec.pop_back();
}
}
};