【问题标题】:Build all possible sorted combinations of a List<string>构建 List<string> 的所有可能的排序组合
【发布时间】:2014-10-25 11:59:17
【问题描述】:
我有一个 .Net 列表,我想知道最(或“合理”接近)有效的方法是以下列方式组合它们:
鉴于列表有 3 个元素(“A”、“B”和“C”),我基本上需要从方法返回以下内容:
- 一个
- B
- C
- A B
- A C
- BC
- A B C
基本上,内部元素的顺序必须保持不变(A > B > C),因此只有例如4.) 上面的 'A B' 是可能的/应该返回,但反过来 ('B A') 则不行。
我一直在摆弄这个问题,但目前我的代码远非优雅,但也许有人已经做过类似的事情并且知道如何正确/有效地做到这一点。
【问题讨论】:
标签:
.net
algorithm
sorting
combinations
【解决方案1】:
我能想到的生成这样的集合的方法有以下三种:
元素的位表示在您的示例中,您可以从 1 迭代到 1 << length(排他性)并从设置的位构建列表:
1 001 {A}
2 010 {B}
3 011 {A, B}
4 100 {C}
5 101 {A, C}
6 110 {B, C}
7 111 {A, B, C}
列表列表本身是有序的,当你反过来做时,即让最高位代表 A 而不是最低位。
二进制递归 递归列表中的元素,在每一步中,您会走两条路径:包括当前元素或丢弃它。您必须在递归时建立一个列表;处理完原始列表的所有元素后,将其添加到结果中。
这可能比每次都从位模式构建列表更有效。它还会生成空列表,你应该特别对待它。
填写以1 << length空列表开头。将第一个元素放在后半部分的所有列表中。将第二个元素放在第二和第四季度的所有列表中。将每个列表中的第三个元素放在第 2、第 4、第 6 和第 8 个八分圆中。等等。这实际上只是递归方法的迭代变体,还将创建空列表。 (它也与位模式解决方案相关。)
【解决方案2】:
目前我认为返回的顺序无关紧要。我将按以下顺序返回元素:
1. A
2. B
3. A B
4. C
5. A C
6. B C
7 A B C
如果这对您不起作用,请回信,我会尝试找出可行的算法。
这个顺序对您来说可能有点奇怪,但如果您迭代所有可能的元素组合,这是您将收到的直截了当的顺序。
对于每种元素组合,我都会在您选择元素的地方分配带有 1 的二进制掩码。因此,A 是第一位,B 是第二位,C 是第三位(我给出的示例包含三个元素,但这显然可以扩展到更多元素)。
A B -> 011 = 3
C -> 100 = 4
B C -> 110 = 6
我将提供 C++ 中的 oyu 伪代码,因为我不是 .Net 的大师,但我相当有信心您能够将其转换为您的语言。
void printCombination(List<Element> elements, int mask) {
int n = elements.size(); // number of elements
for (int i = 0; i < n; i++) {
bool elementPrinted = false;
if (mask & (1 << i)) { //if the ith bit is set
if (elementPrinted) cout << " "; // adding separator
cout << elements.get(i);
elementPrinted = true;
}
cout << "\n";
}
}
void getAllCombinations(List<Element> elements) {
int n = elements.size(); // number of elements
for (int mask = 1; mask < (1 << n); mask++) { // iterate all possible submasks
printCombination(elements, mask);
}
}