列表中包含每个列表中唯一元素的所有可能组合,没有重复元素

时间:2017-12-01 10:24:57

标签: java list recursion combinations

假设我有一个n列表的列表:

例如当n = 3

list1 = ["M","G"]; 

list2 = ["VP","P"];

list3 = ["E"]

输出必须是所有可能组合的列表,其约束条件是每个组合必须包含每个列表中的一个元素。

上述相同示例的输出必须为:

2 * 2 * 1 =每种组合的4种组合必须准确包含3个字符串(每个输入列表一个)。

lists= [ ["M","VP","E"], ["M","P","E"], ["G","VP","E"], ["G","P","E"] ]

我尝试了一个递归函数,但我注意到下面的当前列表在递归过程中不能保留旧版本:

列表 - >包含所有输入列表(例如,list1,list2和list3)

结果 - >包含所有输出列表(所有组合)

当前 - >是目前的组合

public static void combination(ArrayList<ArrayList<String>> lists, ArrayList<ArrayList<String>> result, ArrayList<String> current, int k){
    if(k==lists.size()){
        result.add(current);
        current = new ArrayList<String>();
        System.out.println("(if) || k="+k+" || current"+current);
        return;
    }
    for(int t=0;t<lists.get(k).size();t++){
        current.add(lists.get(k).get(t));
        System.out.println("(for) || k="+k+" || current"+current);
        combination(lists, result, current, k+1);
    }
} 

使用上面相同的示例调用此函数的输出:

public static void main(String[] args){
    ArrayList<String> l1 = new ArrayList<String>();l1.add("M");l1.add("G");
    ArrayList<String> l2 = new ArrayList<String>();l2.add("VP");l2.add("P");
    ArrayList<String> l3 = new ArrayList<String>();l3.add("E");
    ArrayList<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
    ArrayList<ArrayList<String>> result = new ArrayList<ArrayList<String>>();
    ArrayList<String> current = new ArrayList<String>();

    lists.add(l1);lists.add(l2);lists.add(l3);
    combination(lists, result, current, 0);

    for(int i=0;i<result.size();i++){
        System.out.println(result.get(i));
    }

}

输出结果为:

(for) || k=0 || current[M]

(for) || k=1 || current[M, VP]

(for) || k=2 || current[M, VP, E]

(if) || k=3 || current[]

(for) || k=1 || current[M, VP, E, P]

(for) || k=2 || current[M, VP, E, P, E]

(if) || k=3 || current[]

(for) || k=0 || current[M, VP, E, P, E, G]

(for) || k=1 || current[M, VP, E, P, E, G, VP]

(for) || k=2 || current[M, VP, E, P, E, G, VP, E]

(if) || k=3 || current[]

(for) || k=1 || current[M, VP, E, P, E, G, VP, E, P]

(for) || k=2 || current[M, VP, E, P, E, G, VP, E, P, E]

(if) || k=3 || current[]

[M, VP, E, P, E, G, VP, E, P, E]

[M, VP, E, P, E, G, VP, E, P, E]

[M, VP, E, P, E, G, VP, E, P, E]

[M, VP, E, P, E, G, VP, E, P, E]

例如:

这一行:(for) || k=1 || current[M, VP, E, P] 必须是:(for) || k=1 || current[M, VP]

但是当前并没有将旧版本保留在调用它的递归函数中。

2 个答案:

答案 0 :(得分:0)

另一种方法,可能更容易:

public static List<List<String>> combination(List<List<String>> lists){
    if (lists.size() == 1) {
        return lists;
    } else {
        List<List<String>> subcombs = combination(lists.subList(1, lists.size()));
        List<List<String>> result = new ArrayList<>();
        for (String s : lists.get(0)) {
            for (List<String> subcomb : subcombs) {
                List<String> list = new ArrayList<>();
                list.add(s);
                list.addAll(subcomb);
                result.add(list);
            }
        }
        return result;
    }
}

public static void main(String[] args){
    List<String> l1 = Arrays.asList("M", "G");
    List<String> l2 = Arrays.asList("VP", "P");
    List<String> l3 = Arrays.asList("E");
    System.out.println(combination(Arrays.asList(l1, l2, l3)));
    // Output: [[M, VP, E], [M, P, E], [G, VP, E], [G, P, E]]
}

在每个递归步骤中,只需计算子组合并在前面添加当前列表的每个字符串

答案 1 :(得分:0)

我认为这两种方法可以完成这项工作:

public static void main(String[] args) {

    List<String> list1 = Arrays.asList("M,G".split(","));
    List<String> list2 = Arrays.asList("VP,P".split(","));
    List<String> list3 = Arrays.asList("E".split(""));

    List<List<String>> mainList = new ArrayList<>();

    mainList.add(list1);
    mainList.add(list2);
    mainList.add(list3);

    combination(mainList, new ArrayList<>());
}

public static void combination(List<List<String>> remainingListsToUse, ArrayList<String> current)
{
    if(remainingListsToUse.isEmpty())
    {
        System.out.println(current.toString());
        return;
    }

    for(List<String> remainingListToUse : remainingListsToUse)
    {
        List<List<String>> listsToKeepGoingWith = new ArrayList<>();
        listsToKeepGoingWith.addAll(remainingListsToUse);
        listsToKeepGoingWith.remove(remainingListToUse);

        remainingListToUse.forEach(listUsed->{
            ArrayList<String> newCurrent = new ArrayList<>();
            newCurrent.addAll(current);
            newCurrent.add(listUsed);
            combination(listsToKeepGoingWith, newCurrent);
        });
    }
}

我认为可以排列不同的列表......

结果如下:

 [M, VP, E] 
 [M, P, E]
 [M, E, VP]
 [M, E, P]
 [G, VP, E]
 [G, P, E]
 [G, E, VP]
 [G, E, P]
 [VP, M, E]
 [VP, G, E]
 [VP, E, M]
 [VP, E, G]
 [P, M, E]
 [P, G, E]
 [P, E, M]
 [P, E, G]
 [E, M, VP]
 [E, M, P]
 [E, G, VP]
 [E, G, P]
 [E, VP, M]
 [E, VP, G]
 [E, P, M]
 [E, P, G]

希望它会对你有所帮助! :)

编辑:

如果订单和unicity maters你可能更喜欢这种方法:

public static void combination(List<List<String>> remainingListsToUse, ArrayList<String> current)
{
    // If all the lists have been used
    if(remainingListsToUse.isEmpty())
    {
        System.out.println(current.toString());
        return;
    }

    if(!remainingListsToUse.isEmpty())
    {
        List<String> listCurrentlyUsed = remainingListsToUse.get(0);
        List<List<String>> newRemainingListToUse = new ArrayList<>();
        newRemainingListToUse.addAll(remainingListsToUse);
        newRemainingListToUse.remove(listCurrentlyUsed);

        listCurrentlyUsed.forEach(listElementUsed->{
            ArrayList<String> newCurrent = new ArrayList<>();
            newCurrent.addAll(current);
            newCurrent.add(listElementUsed);
            combination(newRemainingListToUse, newCurrent);
        });
    }
}

结果就是这样:

[M, VP, E]
[M, P, E]
[G, VP, E]
[G, P, E]