以递归方式查找arraylist中的所有组合

时间:2015-03-24 04:28:57

标签: java recursion

我完全迷失了。我可以迭代地执行此操作,但递归对我来说是新的。如果给我一个内部有1,2,3的arraylist,那么带有重复的总可能组合是27。

111,112,113,121,122,123等......

我如何递归地找到它?我会展示我的代码,但我甚至没有接近这个概念......

6 个答案:

答案 0 :(得分:3)

您可以使用此概念并制作自己的递归函数。 使用它你可以得到所有可能的组合。

答案 1 :(得分:1)

如果更改了ArrayList的大小,那么解决方案怎么样?

public static void main(String args[]) {
    ArrayList<Integer> ali = new ArrayList<>();
    ali.add(1);
    ali.add(2);
    ali.add(3);

    System.out.println(combinations(ali).toString().replace("], [", "],\n ["));
}

这在开始时只是一点帮助。

public static List<List<Integer>> combinations(List<Integer> input) {
    return step(input, input.size(), new ArrayList<>());
}

这是递归方法,

public static List<List<Integer>> step(List<Integer> input, 
                                       int k, 
                                       List<List<Integer>> result) {

    // We're done
    if (k == 0) {
        return result;
    }

    // Start with [[1], [2], [3]] in result
    if (result.size() == 0) {
        for (Integer i : input) {
            ArrayList<Integer> subList = new ArrayList<>();
            subList.add(i);
            result.add(subList);
        }

        // Around we go again.  
        return step(input, k - 1, result);
    }

    // Cross result with input.  Taking us to 2 entries per sub list.  Then 3. Then... 
    List<List<Integer>> newResult = new ArrayList<>();
    for (List<Integer> subList : result) {
        for(Integer i : input) {
            List<Integer> newSubList = new ArrayList<>();
            newSubList.addAll(subList);
            newSubList.add(i);
            newResult.add(newSubList);
        }
    }

    // Around we go again.  
    return step(input, k - 1, newResult);
}

输出:

[[1, 1, 1],
 [1, 1, 2],
 [1, 1, 3],
 [1, 2, 1],
 [1, 2, 2],
 [1, 2, 3],
 [1, 3, 1],
 [1, 3, 2],
 [1, 3, 3],
 [2, 1, 1],
 [2, 1, 2],
 [2, 1, 3],
 [2, 2, 1],
 [2, 2, 2],
 [2, 2, 3],
 [2, 3, 1],
 [2, 3, 2],
 [2, 3, 3],
 [3, 1, 1],
 [3, 1, 2],
 [3, 1, 3],
 [3, 2, 1],
 [3, 2, 2],
 [3, 2, 3],
 [3, 3, 1],
 [3, 3, 2],
 [3, 3, 3]]

答案 2 :(得分:0)

这是我刚刚在python中制作的硬编码解决方案,但它应该证明原理:

def combinations(original,indexes):
    indexes[2] = indexes[2] + 1
    if(indexes[2] == 3):
        indexes[1] = indexes[1] + 1
        indexes[2] = 0

    if(indexes[1] == 3):
        indexes[0] = indexes[0] + 1
        indexes[1] = 0

    if(indexes[0] != 3):
        print str(original[indexes[0]]) + str(original[indexes[1]]) \
            + str(original[indexes[2]])
        combinations(original, indexes)


combinations([1,2,3],[0,0,0])

注意我是如何使用函数组合()的。此函数将原始数组作为参数,将第二个数组作为跟踪索引。

当我调用该函数启动它时,我将索引数组初始化为全0。

在堆栈中的每个函数中,您应该增加索引数组中的索引以生成正确的输出。注意在我的解决方案中我如何使用三个if语句,这是硬编码部分。这可能是通过for循环完成的。

最后,使用修改后的索引数组再次调用combination()函数内部函数(递归),直到满足end子句(第一个索引已经超出)。

此代码段应作为指导,因为我看到您标记为java

答案 3 :(得分:0)

这是java中的方法:

String combine(ArrayList<Integer> a, String b){
String c="";
   if(b.length()==a.size()){
    System.out.println(b); //found a combo
    return "";
    }
  //append characters to string b
  for(int x=0;x<a.size();x++){
    c=b+((Integer)a.get(x)).intValue();
    c+=combine(a,c);
  }
  return c;
 }

在循环的每次迭代中,它会将一个字符附加到arraylist a中的字符串b并递归调用自身。一旦字符串b的长度达到3(即arraylist a的大小),就意味着生成了一个组合并显示了它。此方法适用于任何大小的arraylist。

答案 4 :(得分:0)

我理解你的斗争。在跟踪所有调用并决定如何导航问题时,递归地解决问题通常很棘手。经过一番思考后,我能够解决这个问题,使用int数组表示排列,使用ArrayList进行存储。 没有使用循环,也没有检查重复。

我编写了一个名为getPermutations的易于调用的方法,它允许您使用整数[1,n]查找长度为n的所有排列。此方法调用实际的递归方法,这有点复杂。在解决这样的问题时,使用方法的参数来跟踪某些数据点很重要,但这会使实际调用方法有点痛苦(因此使用辅助方法) 。我的代码如下所示。

//Recursive Method
public static ArrayList<int[]> permutationsFrom(int[] start,int i, int val, ArrayList<int[]> prev) {
    int n = start.length;
    if (i == n) {
        final int[] perm = start.clone();
        prev.add(perm);
        return prev;
    }
    else if (val > n) {
        return prev;
    }
    else {
        int[] next = start.clone();
        next[i] = val;
        prev.addAll(permutationsFrom(next, i+1, 1, new ArrayList<int[]>()));
        return permutationsFrom(next, i, ++val, prev);
    }
}

//Invokation
public static ArrayList<int[]> getPermutations(int n) {
    return permutationsFrom(new int[n], 0, 1, new ArrayList<int[]>());
}

//Print the results
public static void main(String[] args) {
    ArrayList<int[]> perms = getPermutations(3);
    System.out.println(perms.size());
    for (int[] perm : perms) {
        for (int el : perm) {
            System.out.print(el + " ");
        }
        System.out.println();
    }
}

递归的工作原理:

  • 从完全“未确定”的排列开始:需要找到每个可能的索引的每个可能值

  • 在当前索引i处,递归地调用捕获每个值val的方法,从1到n

  • 已经找到完整的排列当i == n 时(即每个索引已经从0到n-1确定),因此int数组应该被添加到集合中先前的排列,prev

  • 如果 val&gt; n 索引i处的每个可能值(从1到n)都已被计算,因此可以返回集合(此时方法将继续递增i并水平移动)

答案 5 :(得分:0)

这个派对迟到了,&amp;抱歉,它在c#中,但是嘿,它与Java类似。这里的一切看起来都有点复杂,所以这里的函数非常简单,应该很容易翻译成Java -

    public static List<List<T>> Permutations<T>(List<T> list)
    {
        List<List<T>> result = new List<List<T>>();

        for (int i = 0; i < list.Count(); i++)
        {
            T initialValue = list[i];
            List<T> clonedList = list.Where((item, index) => { return index != i; }).ToList(); // proper copy, less the initialValue item

            // here's where the recursion happens, but only if there are at least 2 items left in the list
            List<List<T>> permutations = clonedList.Count > 0 ? Permutations(clonedList) : new List<List<T>> { new List<T>() };

            foreach (List<T> permutation in permutations)
            {
                List<T> combined = new List<T> { initialValue };
                combined.AddRange(permutation);

                result.Add(combined);
            }
        }

        return result;
    }