【问题标题】:List of all possible combinations with unique element from each list without duplicate elements每个列表中具有唯一元素的所有可能组合的列表,没有重复元素
【发布时间】:2018-05-15 10:27:43
【问题描述】:

假设我有一个包含 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"] ]

我尝试了一个递归函数,但我注意到下面的当前列表在递归期间无法保留旧版本:

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

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

current -> 是当前的组合

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]

但 current 不会将其旧版本保留在调用它的递归函数中。

【问题讨论】:

  • 您没有处理 Java 始终为 pass-by-value 的事实。当您执行current = new ArrayList&lt;String&gt;(); 时,您不会修改先前递归调用的current 列表,而只是修改方法内“当前”列表的值。

标签: java list recursion combinations


【解决方案1】:

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

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]]
}

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

【讨论】:

  • 例如,您的方法不适用于 4 个列表!
  • 你确定吗?它应该适用于任意数量的列表,它不特定于 3 个列表......你能提供一个我的方法不起作用的测试用例吗?
【解决方案2】:

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

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]

希望对你有帮助! :)

编辑:

如果顺序和唯一性很重要,您可能更喜欢这种方法:

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]

【讨论】:

  • 这不是我想要的,因为在我的情况下,秩序和单一性是重要的限制因素。
  • 好吧,我不知道。稍后我会花时间更正我的答案:)
猜你喜欢
  • 1970-01-01
  • 2018-11-11
  • 1970-01-01
  • 1970-01-01
  • 2023-02-14
  • 1970-01-01
  • 2021-12-16
  • 1970-01-01
  • 2013-06-01
相关资源
最近更新 更多