我正在寻找一种能够在不重复的情况下生成第n个组合的算法。
我可以在(a, b) != (b, a)
的排列中找到很多,但我正在寻找{a, b} = {b, a}
的组合。
示例:
Set = {a, b, c}
n = 2
Combinations: {a, b}, {a, c}, {a, d}, {b, c}, {b, d}, {c, d}
Java中使用Set或List的通用递归实现会很棒。我也很感激与一个很好的解释,伪或示例代码的链接。
答案 0 :(得分:3)
递归算法很简单:
答案 1 :(得分:3)
你还记得找到k-th permutations of the elements的问题吗?并不是很多人都知道算法背后的原因,但它背后有一个数学理论。它可以通过在factorial number system中表示数字来解决。
如果问题是关于找到第k个组合,我为什么要谈论第k个排列?只因为它可以用类似的数学理论来解决。令人惊讶的是,有一个combinatorial number system:
集合S的k-组合是S的子集,具有k(不同) 元素。组合数系统的主要目的是 提供一个代表,每个代表一个数字 {\ displaystyle {\ tbinom {n} {k}}}集合S的可能k组合 n个元素。
阅读文章,很可能您将能够解决您的问题。
答案 2 :(得分:3)
根据输入list
和n
,将list
拆分为第一项,列表的其余部分将其称为head
和tail
。然后,您寻求的组合是:
tail
和n
获得的组合,以及tail
和n-1
获得的组合,每个组合都有head
前置如果n
为0,则结果只有一个组合:{}
如果n
大于list
,则结果为无组合
旁注:为了好玩,我在Haskell中解决了这个问题,将n
= 0个案放在了最上面:
comb 0 _ = [[]]
comb n (head:tail) | n > 0 = comb n tail ++ map (head:) (comb (n-1) tail)
comb _ _ = []
答案 3 :(得分:1)
您可以使用以下递归方法执行此操作:
public static<T> ArrayList<ArrayList<T>> getPermutations (List<T> elements, int k) {
return getPermutations (elements,k,0);
}
public static<T> ArrayList<ArrayList<T>> getPermutations (List<T> elements, int k, int i) {
ArrayList<ArrayList<T>> results = new ArrayList<>();
if(k > 0) {
int n = elements.size();
for(int j = i; j <= n-k; j++) {
T val = elements.get(j);
ArrayList<ArrayList<T>> tails = getPermutations(elements,k-1,j+1);
for(ArrayList<T> tail : tails) {
ArrayList<T> result = new ArrayList<>();
result.add(val);
result.addAll(tail);
results.add(result);
}
}
} else {
results.add(new ArrayList<T>());
}
return results;
}
然后您可以使用(jDoodle):
运行它ArrayList<Character> set = new ArrayList<>();
set.add('a');
set.add('b');
set.add('c');
for(ArrayList<Character> element : getPermutations(set,2)) {
System.out.println(element);
}
System.out.println("----------");
for(ArrayList<Character> element : getPermutations(set,3)) {
System.out.println(element);
}
System.out.println("----------");
set.add('d');
for(ArrayList<Character> element : getPermutations(set,2)) {
System.out.println(element);
}
System.out.println("----------");
for(ArrayList<Character> element : getPermutations(set,3)) {
System.out.println(element);
}
生成:
[a, b]
[a, c]
[b, c]
----------
[a, b, c]
----------
[a, b]
[a, c]
[a, d]
[b, c]
[b, d]
[c, d]
----------
[a, b, c]
[a, b, d]
[a, c, d]
[b, c, d]
该程序的工作原理如下:k
是我们仍需要选择的元素数,i
是当前的偏移值。最初该偏移值为0
。
现在我们从i
迭代到n-k
,寻找潜在的候选人参与其中。该范围内的每个元素都是某些组合的头部。我们对列表的其余部分执行递归。递归生成在列表的其余部分上采用 k-1 元素的所有列表。然后我们的工作就是在前面添加一个头并返回列表。
通过使用特殊形式的LinkedList
(在逻辑和函数式编程语言中很常见),您可以更快,更保守地实现这一点。