我想计算你可以制作一组的所有可能的对列表。例如:
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
的输入:(。我还没有实现所有内容,但我想它会运行一段时间:(。
答案 0 :(得分:4)
如果我理解正确,那么这个问题的递归解决方案应该相当简单:
添加和删除元素的部分并不真正包含在此示例实现中,因为它为迭代和递归调用创建了一个列表和一个新集合,但这个想法应该是明确的。
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)*...
确实是选择
这里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)]
注意:我没有尝试使用聪明的数据结构进行优化。特别是,使用双向链表可以避免复制choice
和l1
。
答案 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)