Java 递归查找arraylist中的所有组合

Java 递归查找arraylist中的所有组合,java,recursion,Java,Recursion,我完全不明白这一点。我可以迭代地这样做,但是递归对我来说是新的。如果给我一个里面有1,2,3的arraylist,那么可能的重复组合总数是27 111、112、113、121、122、123等 我怎样才能递归地找到它?我将展示我的代码,但我甚至还没有接近概念…这里是我刚刚用python制作的硬编码解决方案,但它应该演示以下原则: def combinations(original,indexes): indexes[2] = indexes[2] + 1 if(indexes[2

我完全不明白这一点。我可以迭代地这样做,但是递归对我来说是新的。如果给我一个里面有1,2,3的arraylist,那么可能的重复组合总数是27

111、112、113、121、122、123等


我怎样才能递归地找到它?我将展示我的代码,但我甚至还没有接近概念…

这里是我刚刚用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循环实现的

最后,函数thecombines()函数将使用修改后的索引数组在其内部再次调用(递归),直到满足end子句(第一个索引已最大化)


这个代码片段应该作为指导,因为我看到您标记了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;
 }
字符串组合(数组列表a、字符串b){
字符串c=“”;
如果(b.length()==a.size()){
System.out.println(b);//找到一个组合
返回“”;
}
//将字符附加到字符串b

对于(intx=0;x,您可以使用这个概念并创建自己的递归函数。 使用它可以得到所有可能的组合


如果您更改了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 ["));
}

我理解你的苦衷。在跟踪所有调用并决定如何导航问题时,递归解决问题往往很棘手。经过一点思考,我能够解决这个问题,使用int数组表示置换,使用ArrayList存储。没有使用循环,也没有检查重复。

我编写了一个易于调用的方法,名为getPermutations,它允许您查找长度为n的整数[1,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();
    }
}
//递归方法
公共静态ArrayList排列来自(int[]开始,int i,int val,ArrayList prev){
int n=起始长度;
如果(i==n){
final int[]perm=start.clone();
上一次添加(perm);
返回上一个;
}
否则如果(val>n){
返回上一个;
}
否则{
int[]next=start.clone();
next[i]=val;
prev.addAll(permutationsFrom(next,i+1,1,newarraylist());
返回排列from(next,i,++val,prev);
}
}
//援引
公共静态数组列表getPermutations(int n){
从(new int[n],0,1,new ArrayList())返回置换;
}
//打印结果
公共静态void main(字符串[]args){
ArrayList perms=getPermutations(3);
System.out.println(perms.size());
for(int[]perm:perms){
用于(整数el:perm){
系统输出打印(el+“”);
}
System.out.println();
}
}
递归的工作原理:

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

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

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

  • 如果val>n索引i处的所有可能值(从1到n)都已计算在内,则可以返回集合(此时方法将继续递增i并水平移动)


这次聚会有点晚了,&抱歉,它是用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;
    }
公共静态列表排列(列表)
{
列表结果=新列表();
对于(int i=0;i{return index!=i;}).ToList();//正确的副本,减去initialValue项
//这里是递归发生的地方,但前提是列表中至少剩下2项
列表置换=clonedList.Count>0?置换(clonedList):新列表{new List()};
foreach(排列中的列表排列)
{
组合列表=新列表{initialValue};
组合。添加范围(置换);
结果:添加(合并);
}
}
返回结果;
}

您指的是长度3的总组合。递归的一部分可能涉及到查找长度2的总组合。然后,您需要为每个较短的组合添加一个额外的字符。因此,我认为长度将是递归的索引。请考虑递归的基本步骤可能是什么。
[[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]]
//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();
    }
}
    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;
    }