如何使用Java在列表中找到所有可能的4个组?

时间:2014-05-16 02:11:24

标签: java algorithm combinations permutation combinatorics

假设我有一个字母列表:

String list[] = {"A","B","C","D","E","F","G","H","I","J"};

使用Java在列表中查找所有可能的4个组的最简单方法是什么(假设顺序不重要,这意味着ABCD与DCBA相同)?

我遇到了这个What's the quickest way to find all possible pairs in list?,我尝试通过这样做扩展解决方案:

    for(int i=0;i<=list.length-4;i++){
        for(int j=i+1;j<=list.length-3;j++){
            for(int k=i+2;k<=list.length-2;k++){
                for(int l=i+3;l<=list.length-1;l++){
                    System.out.println(list[i]+","+list[j]+","+list[k]+","+list[l]);
                }
            }
        }
    }
}

但很明显,这是不对的。如果有人可以帮助提供解决方案,这是上述链接的解决方案的扩展,那将是很好的。谢谢!

2 个答案:

答案 0 :(得分:3)

我怀疑这是最快的,或者说无论如何都是最有效的,但我喜欢它(而且它更通用)。

这基本上是为了从n个元素的(排序)列表中获取大小为k的所有组合,依次取每个n-k + 1个第一个元素,并附加大小为k-1的所有组合。之后的清单。

要终止递归,如果k = 1,只需返回每个元素的单例列表列表。

为了使这个具体,在你的例子中,它确实:

“A”,包含来自“B”的3个字母的所有可能组合 - 附加“J”

一起

“B”,包含来自“C” - “J”的3个字母的所有可能组合

一起

“C”,包含来自“D” - “J”的3个字母的所有可能组合

...

“F”,包含来自“G” - “J”的3个字母的所有可能组合

一起

“G”,包含“H”的3个字母的所有可能组合 - 附加“J”(只有1个)

要获得“B” - “J”中3个字母的所有可能组合,它确实

“B”,包含来自“C” - “J”的2个字母的所有可能组合

一起

“C”,包含来自“D” - “J”的2个字母的所有可能组合

关于列表的初始排序,组合按字典顺序生成。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class Combinatorics {

    /**
     * Computes all combinations of items of size <code>size</code>
     * Assumes that items contains no replicates<
     * @param items
     * @param size
     * @return A List of all possible Lists of items, each List of size <code>size</code>.
     */
    public static <T extends Comparable<? super T>> List<List<T>> combinations(List<T> items, int size) {
        if (size == 1) {
            List<List<T>> result = new ArrayList<>();
            for (T item : items) {
                result.add(Collections.singletonList(item));
            }
            return result ;
        }
        List<List<T>> result = new ArrayList<>();
        for (int i=0; i <= items.size() - size; i++) {
            T firstItem = items.get(i);
            List<List<T>> additionalItems = combinations(items.subList(i+1, items.size()), size-1) ;
            for (List<T> additional : additionalItems) {
                List<T> combination = new ArrayList<>();
                combination.add(firstItem);
                combination.addAll(additional);
                result.add(combination);
            }
        }
        return result ;
    }

    public static void main(String[] args) {
        List<String> values = Arrays.asList("A", "C", "B", "D", "E", "F", "G", "H", "I", "J");
        List<List<String>> allCombinations = combinations(values, 4);
        for (List<String> combination : allCombinations) {
            System.out.println(combination);
        }
        System.out.println(allCombinations.size() + " total combinations");
    }
}

答案 1 :(得分:2)

你很接近试试这个。

for(int i=0;i<=list.length-4;i++){
    for(int j=i+1;j<=list.length-3;j++){
        for(int k=j+1;k<=list.length-2;k++){// change i+2 to j+1
            for(int l=k+1;l<=list.length-1;l++){// change i+3 to k+1
                System.out.println(list[i]+","+list[j]+","+list[k]+","+list[l]);
            }
        }
    }
}

修改

i + x初始化会导致问题,因为它们是静态偏移,并且可以防止索引冲突。即,当j增量j+1将等于i+2导致碰撞时。通过使偏移j+1而不是i+2,它成为相对于j防止碰撞的动态偏移。