一组内所有对的组合

时间:2014-02-13 17:49:28

标签: java algorithm collections combinations

我想计算你可以制作一组的所有可能的对列表。例如:

input = [1, 2, 3, 4, 5, 6]

output = {[(1,2), (3,4), (5,6)],
          [(2,3), (4,5), (1,6)],
          [(2,4), (1,3), (5,6)],
          [...], .... }

注意:此示例只是输出中的一些随机内容,大多数都被删除。我不关心列表的顺序或这些列表中的对。

我认为会有(n-1)(n-3)(n-5)...个可能的对名单。首先,我认为你可以对输入列表进行所有排列。通过所有这些排列,您可以将第一个与第二个项目分组,第三个与第四个组合。但显然这是非常低效的,因为你会在列表中制作n!项,而你只需要(n-1)(n-3)(n-5)...。有些人可以给我一个如何更有效地做到这一点的提示吗?是否有已知算法或搜索适当的关键字?我想在JAVA中实现这个,所以如果你想在JAVA中使用Collections类没问题:)

更清楚:输入总是由偶数个元素组成,因此一个列表中的所有对都是输入中的所有元素。

修改 我看到了所有答案。现在我有工作代码,谢谢你。但我需要将它用于大小为n = 26的输入:(。我还没有实现所有内容,但我想它会运行一段时间:(。

5 个答案:

答案 0 :(得分:4)

如果我理解正确,那么这个问题的递归解决方案应该相当简单:

  • 从集合
  • 中删除第一个元素A.
  • 对于每个剩余的元素B:
    • 从集合中删除元素B
    • 创建一对(A,B)并将其存储为当前解决方案的一部分
    • 使用剩余的设置进行递归。这将为当前解决方案添加更多对。如果集合中没有剩余元素,则将当前解决方案存储为最终解决方案之一。
    • 将元素B添加到集合
  • 将元素A添加到集合

添加和删除元素的部分并不真正包含在此示例实现中,因为它为迭代和递归调用创建了一个列表和一个新集合,但这个想法应该是明确的。

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

public class AllPairs
{
    public static void main(String[] args)
    {
        Set<Integer> set = new LinkedHashSet<Integer>(
            Arrays.asList(1,2,3,4,5,6));

        ArrayList<List<List<Integer>>> results = 
            new ArrayList<List<List<Integer>>>();
        compute(set, new ArrayList<List<Integer>>(), results);
        for (List<List<Integer>> result : results)
        {
            System.out.println(result);
        }
    }

    private static void compute(Set<Integer> set,
        List<List<Integer>> currentResults,
        List<List<List<Integer>>> results)
    {
        if (set.size() < 2)
        {
            results.add(new ArrayList<List<Integer>>(currentResults));
            return;
        }
        List<Integer> list = new ArrayList<Integer>(set);
        Integer first = list.remove(0);
        for (int i=0; i<list.size(); i++)
        {
            Integer second = list.get(i);
            Set<Integer> nextSet = new LinkedHashSet<Integer>(list);
            nextSet.remove(second);

            List<Integer> pair = Arrays.asList(first, second);
            currentResults.add(pair);
            compute(nextSet, currentResults, results);
            currentResults.remove(pair);
        }
    }
}

答案 1 :(得分:1)

修改:我以前的帖子有些错误。我没有处理OP的句子“我不关心列表的顺序或这些列表中的对”。

你所要求的是完美的配对(匹配)。对的数量是n *(n + 1)/ 2,但配对的数量是(n-1)*(n-3)*(n-5)*...确实是选择

  • 选择与1:(n-1)选项配对的人
  • 选择与剩余最小元素配对的人:(n-3)选择
  • 选择与剩余最小元素配对的人:(n-5)选择
  • ...

这里5 * 3 * 1 = 15.我不是经验丰富的java用户,所以我用Python编写。我正在使用递归算法。

def pairing(l):
    def rec(l, choice):
        if l == []:
            print choice
        else:
            for j in range(1, len(l)):
                choice1 = choice + [(l[0],l[j])]
                l1 = copy(l)
                del l1[j]
                del l1[0]
                rec(l1, choice1)
    rec(l, [])

给出了:

[(1,2),(3,4),(5,6)] [(1,2),(3,5),(4,6)] [(1,2),(3,6),(4,5)] [(1,3),(2,4),(5,6)] [(1,3),(2,5),(4,6)] [(1,3),(2,6),(4,5)] [(1,4),(2,3),(5,6)] [(1,4),(2,5),(3,6)] [(1,4),(2,6),(3,5)] [(1,5),(2,3),(4,6)] [(1,5),(2,4),(3,6)] [(1,5),(2,6),(3,4)] [(1,6),(2,3),(4,5)] [(1,6),(2,4),(3,5)] [(1,6),(2,5),(3,4)]

注意:我没有尝试使用聪明的数据结构进行优化。特别是,使用双向链表可以避免复制choicel1

答案 2 :(得分:0)

您可以使用番石榴Sets#cartesianProduct

Set<List<Integer>> product = Sets.cartesianProduct(ImmutableList.of(ImmutableSet.of(1, 2, 3, 4, 5, 6),ImmutableSet.of(1, 2, 3, 4, 5, 6)));

这将产生:

[[1, 1], [1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [2, 6], [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6], [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [4, 6], [5, 1], [5, 2], [5, 3], [5, 4], [5, 5], [5, 6], [6, 1], [6, 2], [6, 3], [6, 4], [6, 5], [6, 6]]

然后您可以删除[1, 1]等元素

答案 3 :(得分:0)

在某人的脑海中出现的第一件事是Permutaions或Collections方式,你已经提到的效率不高。

让我们从一个问题开始,你对二进制数字感到满意吗? 它们有一个真正的特殊功能,它们只能代表两种状态,即存在(1)或缺席(0)。

如果您正在寻找快速编码解决方案,请转到此处。如果您有兴趣学习这个概念,请进一步阅读:

public class Test {
public static void main(String[] args) {
    int[] input = new int[] {1, 2, 3, 4, 5, 6};
    Test s = new Test();
    s.method(input);
}

public void method(int [] x){
    for( int i = 0 ; i < 1<<x.length ; i++){

        if( Integer.bitCount(i) == 2){
            System.out.println(x[getIndex(Integer.highestOneBit(i))]+", "+x[getIndex(Integer.lowestOneBit(i))]);


        }
    }
}

private int getIndex(int i ){
    if((i & 0) == 1)
        return 0;
    if((i>>1 & 1) == 1 )
        return 1;
    if((i>>2 & 1) == 1 )
        return 2;
    if((i>>3 & 1) == 1 )
        return 3;
    if((i>>4 & 1) == 1 )
        return 4;
    if((i>>5 & 1) == 1 )
        return 5;
    if((i>>6 & 1) == 1 )
        return 6;
    return 0;
}
}

<强>说明: 我们假设我们有三个字符(a,b,c),我们想找到所有对:

现在假设一个三位整数,让我们记下三位的所有可能整数:

 000 --- 0
 001 --- 1
 010 --- 2
 011 --- 3
 100 --- 4
 101 --- 5
 110 --- 6
 111 --- 7

现在用两个高位选择所有数字,即(3,5,6) 现在从第一个数字3中选择高位的索引,所以

The first pair would be index 1 and 2 - b, c
The second pair would be index 0 and 2 - a, b
The third pair would be index 2 and 1 - a, b

答案 4 :(得分:-1)

我也遇到了同样的问题。我只是遵循 Marco13 算法。并编写了这段代码段来打印给定列表中所有可能的元素对。感谢Marco13.

    public static void getAllPairs(List<Integer> list) {
        if (list.size() == 0)
            return;
        getAllPairs(list.subList(1, list.size()));
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(0) + ", " + list.get(i));
        }

    }
相关问题