首页 > 试题广场 >

组合

[编程题]组合
  • 热度指数:11805 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
给出两个整数n和k,返回从1到n中取k个数字的所有可能的组合
例如:
如果n=4,k=2,结果为
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
示例1

输入

2,1

输出

[[1],[2]]
示例2

输入

3,1

输出

[[1],[2],[3]]
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);
        }
    }

}

编辑于 2018-06-06 21:00:11 回复(0)
更多回答
//清晰简单的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;
    }
};

发表于 2017-03-27 20:45:00 回复(3)
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);
    }
};

发表于 2016-08-05 14:21:14 回复(0)
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];
    }
};

//没用递归整的

发表于 2019-04-15 21:36:48 回复(0)
其它套路参考,归纳共性http://blog.csdn.net/versencoder/article/details/52072350

编辑于 2016-07-30 20:03:45 回复(2)
一共10行代码,利用递推公式C(n, k) = C(n - 1, k - 1) + C(n - 1, k)
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))

发表于 2017-10-07 14:52:29 回复(0)
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);
	}
};

发表于 2017-09-10 01:03:40 回复(0)
//这个题目与“和为定值的多个数”非常相似,可以用同一种思路求解,所以做一个简单
//归纳,如果再遇见相似题目会继续加入进来。
#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;
    }
};

编辑于 2017-09-10 11:23:47 回复(0)
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;
    }
};

上面有注释,下面是死路。。哦不,下面是思路,嘿嘿::
    参数中 有个 K ,最直接的想法 就是 写 K 个循环 ,但坑爹的是,K是个 变量 ,是在写不出来;
那么递归 来啦,,我们想一下 多叉树 要 怎么递归遍历 , 是的 一个子树一个子树 的走 就OK 啦;
这个也是一样,只要 掌握 好 每一层 需要从哪里 开始 和 到哪里结束 就 成功了 2/3;
就这些 ,之后的看代码吧;      66666
编辑于 2015-09-07 15:40:42 回复(0)
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();
        }
    }
};


发表于 2020-05-21 10:03:34 回复(0)
//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 ;
    }
};

发表于 2019-06-11 15:15:34 回复(0)
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);
        }

    }
}

发表于 2018-04-03 10:18:06 回复(0)
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;
    }
}


编辑于 2018-03-21 13:34:44 回复(0)
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);
    }
  }
}

发表于 2017-12-19 00:54:55 回复(0)
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();
        }
    }
};

发表于 2017-07-25 23:12:41 回复(0)
 

import java.util.*;
public class Solution {
   
    public void trackback(Stack<Integer>s,ArrayList<ArrayList<Integer>>list,int t,int k,int n)
    {
        if(k==0){
            ArrayList<Integer>temp=new ArrayList<Integer>();
            for(int te:s)
                {
            
                temp.add(te);
               
            }
            list.add(temp);
            return;
   
        }
        if(t>n){
            return ;
        }
               
      s.push(t);
       
      trackback(s,list,t+1,k-1,n);
        s.pop();
        trackback(s,list,t+1,k,n);
       
    }
   
   
    public ArrayList<ArrayList<Integer>> combine(int n, int k) {
      
        ArrayList<ArrayList<Integer>>list=new ArrayList<ArrayList<Integer>>();
        Stack<Integer>s=new Stack<Integer>();
        trackback(s,list,1,k,n);
  
        return list;
       
       
       
    }

发表于 2017-07-03 10:36:24 回复(0)
// 朴素回溯,每次都递归地从当前选中元素后面的元素中选
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;
    }
};
发表于 2022-12-07 21:30:49 回复(0)
## 二叉树思路,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


发表于 2022-12-19 14:32:58 回复(0)

回溯:

//
// 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();
        }
    }
};
发表于 2020-09-24 17:55:52 回复(0)
import java.util.*;


public class Solution {
    /**
     * 
     * @param n int整型 
     * @param k int整型 
     * @return int整型ArrayList<ArrayList<>>
     */
    private ArrayList<ArrayList<Integer>> res = new ArrayList<>();
    public ArrayList<ArrayList<Integer>> combine (int n, int k) {
       if (n <=0 || k <= 0){
            return new ArrayList<>();
        }
        //从1开始
        backTrack(1,n,k,new ArrayList<>());
        return res;
    }
    
    public void backTrack(int start,int n, int k, ArrayList<Integer> list){
        if (list.size() == k){
            res.add(new ArrayList<>(list));
        }else {
            for (int i = start; i <= n ; i++) {
                list.add(i);
                //递归寻找下一个值,从i+1开始
                backTrack(i+1,n,k,list);
                //回溯
                list.remove(list.size() - 1);
            }
        }
    }
}
编辑于 2020-09-15 19:27:40 回复(0)