[LeetCode]Combinations

来源:互联网 发布:php后端开发需要学什么 编辑:程序博客网 时间:2024/05/20 10:20

Question
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],]

本题难度Medium。有2种算法分别是: 回溯法和公式法

1、回溯法

【复杂度】
时间 O(N) 空间 O(N)

【思路】
通过深度优先搜索,回溯出所有可能性即可。

【注意】
本来这道题我打算用 [LeetCode]Permutations的方法,排除掉排列中的逆序,取长度为k的序列就是。不过这个方法效率低下,原因在于有太多非法序列。我们在做题目时候可以套用其他的方法,不过要知道有的方法换过来用只是一种生搬硬套,不能最大限度贴近问题特点,而且思维很容易僵化没有创新。

对于本题,关键就在于“不回头”,就是不要有逆序排列。不要用 [LeetCode]Permutations里面的remain,而是直接使用变量i(20-23行),这样可以最大避免使用对象带来的side effect。

【代码】

public class Solution {    public List<List<Integer>> combine(int n, int k) {        //require        List<List<Integer>> ans=new LinkedList<>();        if(n<1||n<k)            return ans;        List<Integer> list=new LinkedList<Integer>();        //invariant        helper(list,1,n,k,ans);        //ensure        return ans;    }    private void helper(List<Integer> list,int start,int n,int k,List<List<Integer>> ans){        //base case        if(k==0){            ans.add(new LinkedList(list));            return;        }        for(int i=start;i<=n;i++){            list.add(i);            helper(list,i+1,n,k-1,ans);            list.remove(list.size()-1);        }    }}

2、公式法

【复杂度】
时间 O(N) 空间 O(N)

【思路】
在数学中,组合数有这么一个性质
这里写图片描述
所以,我们可以分别求出C(n-1,k-1)C(n-1,k),并将前者都加上n,最后将两个结果和到一起,就是C(n,k)。而递归的Base条件是当n=0,k=0或者n<k时,返回一个空列表。

【注意】
C(n-1,k-1)返回的是空列表时,要加一个空列表进去,否则for循环会被跳过

【代码】

public class Solution {    public List<List<Integer>> combine(int n, int k) {        // Recursion: C(n, k) = C(n-1, k-1) U n + C(n-1, k)        // Base: C(0, k) C(n, 0) n < k ---> empty        List<List<Integer>> res = new LinkedList<List<Integer>>();        if(n < k || n == 0 || k == 0){            return res;        }        // C(n-1, k-1) U n        List<List<Integer>> temp = combine(n-1, k-1);        List<List<Integer>> part1 = new LinkedList<List<Integer>>();        // 加入一个空列表,防止跳过for循环        if(temp.isEmpty()){            List<Integer> list = new LinkedList<Integer>();            temp.add(list);        }        for(List<Integer> list : temp){            list.add(n);            part1.add(list);        }        // C(n-1, k)        List<List<Integer>> part2 = combine(n-1, k);        res.addAll(part1);        res.addAll(part2);        return res;    }}

参考

[Leetcode] Combinations 组合数

0 0
原创粉丝点击