【问题标题】:Combination VS Permutation using Recursion使用递归的组合 VS 排列
【发布时间】:2015-12-02 09:18:57
【问题描述】:

我最近在练习算法题。我发现了两个非常相似的问题,并将它们放在一起用于学习目的。

问题 1:拥有来自 n 的所有 k 个组合 - 例如n=4 和 k=3 然后我们返回 {[1,2,3],[1,3,4],[2,3,4],[1,2,4]}

答案:

public static List<List<Integer>> combine(int n, int k) {
    List<List<Integer>> res = new ArrayList<List<Integer>>();
    if(k > n || n <= 0) {
        return res;
    }
    ArrayList<Integer> a = new ArrayList<Integer>();
    helper(res, n, k, 1, a);
    return res;
}

private static void helper(List<List<Integer>> res, int n, int k, int start, ArrayList<Integer> a) {
    if(a.size() == k){
        res.add(new ArrayList<Integer>(a));
        return;
    }

    for(int i=start; i<=n; i++) {
        a.add(i);
        helper(res, n, k, i+1, a);
        a.remove(a.size()-1);
    }
}

问题 2:具有数组的所有排列:{1,2,3} -> {123},{132},{213},{231},{321},{312}。

答案:

public static List<List<Integer>> permute(int[] num) {
    List<List<Integer>> rst = new ArrayList<List<Integer>>();
    if (num == null || num.length == 0) {
        return rst; 
    }

    ArrayList<Integer> list = new ArrayList<Integer>();
    helper(rst, list, num);
    return rst;
}

public static void helper(List<List<Integer>> rst, ArrayList<Integer> list, int[] num){
    if(list.size() == num.length) {
        rst.add(new ArrayList<Integer>(list));
        return;
    }

    for(int i = 0; i<num.length; i++) {
        if(list.contains(num[i])){
            continue;
        }
        list.add(num[i]);
        helper(rst, list, num);
        list.remove(list.size() - 1);
    }
}

对于问题2,我们从索引0开始;对于问题1,为什么for循环索引需要从start开始,为什么我们需要传递一个start参数给helper方法?

【问题讨论】:

  • 顺便说一下,permute(n) = combine(n, n),所以不需要两个单独的实现
  • 不,它们是不同的。 Combine(3,3) 只会给出 (1,2,3) 的结果 ....
  • @NiklasB。是的,不是出生或受教育的英语使用者,我最初的想法是一样的,所以我查了一下,发现Combination vs. Permutation的这个很好的解释
  • @catlovespurple,标签dfs是什么意思?
  • @AntonDanilov 深度优先搜索...

标签: java algorithm recursion depth-first-search


【解决方案1】:

看到 Prolog 代码不要感到惊讶。我认为这有助于从不同的角度看待问题。

组合是包含给定数量元素的集合的任意子集。元素的顺序无关紧要。

comb(0,_,[]).
comb(N,[X|T],[X|Comb]):-N>0,N1 is N-1,comb(N1,T,Comb).
comb(N,[_|T],Comb):-N>0,comb(N,T,Comb).

列表L的排列是一个包含列表L所有元素的列表。

perm(List,[H|Perm]):-select(H,List,Rest),perm(Rest,Perm).
perm([],[]).

select(X,[X|T],T).
select(X,[H|T],[H|NT]):-select(X,T,NT).

所以我的答案是:

我们需要组合情况下的起始索引来指定子集大小。

【讨论】:

    猜你喜欢
    • 2012-10-24
    • 2013-06-13
    • 2013-01-07
    • 1970-01-01
    • 2017-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多