我需要一个算法,它会从6个列表中生成2个3个字符的列表。例如,我有一个包含[a,b,c,d,e,f]
的数组,我想创建[a,b,c][d,e,f]
之类的组合。
我需要获得2次3个字符的所有可能组合。
约束
[a,b,c][d,e,f]
,则我无法[b,a,c][f,d,e]
作为另一种可能性或[f,d,e][b,a,c]
。我理想情况下,如果算法是在javascript中,但我可以接受任何其他建议(我可以阅读代码,即使我不知道我最有可能的语言能够用我不知道的语言理解算法。我看了很多关于排列和组合的帖子和问题,但似乎没有一个我正在寻找的东西,我似乎无法弄清楚如何修改它们以适应我所做的事情。我正在寻找。
答案 0 :(得分:2)
要避免[a,b,c]
⇆[a,c,b]
重复,请从" a"中挑选第一个播放器。到第二个玩家之后,第二个玩家在第二个玩家之后直到#34; e"和第三个玩家在第二个玩家之后直到" f"。
要避免[a,b,c][d,e,f]
⇆[d,e,f][a,b,c]
重复,请保持玩家" a"在第一队。
这是最简单的代码:(它为一个团队挑选人员;第二个团队显然由其他3人组成)
function distribute(n) {
for (var i = 1; i < 5; i++) {
for (var j = i + 1; j < 6; j++) {
document.write("team 1: " + n[0] + ", " + n[i] + ", " + n[j] + "<br>");
}
}
}
distribute(["a","b","c","d","e","f"]);
&#13;
答案 1 :(得分:2)
在这个问题中要注意的主要事情是:我们不需要构建三个项目的第二个列表,一旦我们构建了第一个列表的三个项目,第二个列表只是第一个列表的补充
示例强>:
假设我们选择3个项目为[a , b , c]
,第二个列表简单地为
[a , b , c , d , e , f]
- [a , b , c]
= [d , e , f]
因此,我们只关注第一个列表( list 1 )。
让我们专注于任何一个元素,比如说a
(任意采取)。我们观察到:
每个可能的组合总是a
作为某个列表的成员,在两个列表中,以及包含a
的任何一个,我们称之为列表1 。让我们选择list 1
的其他成员。
我们选择了第一个成员。可以从[b , c , d , e , f]
中选择第二个成员。
在我们算法的第一次迭代中,我们将选择第二个成员为b
。第三个成员可以有四个可能性。这意味着我们必须从[c , d , e , f]
中选择一个元素。一旦我们选择了第三个成员,我们的list 1
就完成了,list 2
也是如此。当第三个成员被认为具有所有4种可能性时,第一次迭代就完成了。
在我们算法的第二次迭代中,我们将选择第二个成员为c
。现在第三个成员只有3种可能性,而 NOT 4,因为我们已经考虑了b。这三种可能性为[d , e , f]
。一旦我们选择了第三个成员,我们的list 1
就完成了,list 2
也是如此。当第三个成员被认为具有所有3种可能性时,第二次迭代就完成了。
同样,在第三次迭代中,我们的第二个成员将是d
,我们将为第三个成员[e , f]
提供2个可能性。
同样,在第四次迭代中,我们的第二个成员将是e
,我们将只有一个可能性为第三个成员f
。
注意强>
我们不必担心算法会有多少次迭代,我们算法的终止条件将是6choose3/2
= 10
的可能组合的总数。
使用的数据结构
我们是否会使用长度为6 arr
的位数组,对于list 1
的每个组合,我们将1
放在相应的位置。因为它将被初始化为0,所以对于每个0,它意味着list 2
的成员。
含义list 1
= [a , b , c]
,然后arr
= [1,1,1,0,0,0]
我们算法的伪代码如下:
Initialize an array of character of length 6 namely set = [a , b , c , d , e , f]
Initialize an array of integer(or boolean to save space cause we will be storing only 0
and 1) of length 6 namely arr,initialized to 0.
int x = 10, total = 0,i = 1.
arr[0] = 1// because element a belongs to list 1
while(total < x)
{
arr[i] = 1
for(j = i + 1 to 5)
{
arr[j] = 1
list 1 is made of all elements set[k] such that arr[k] = 1
list 2 is made of all elements set[k] such that arr[k] = 0
arr[j] = 0
}
total = total + 5 - i
arr[i] = 0
i = i + 1
}
伪代码很容易理解,应该很容易编码。把它作为练习。
答案 2 :(得分:1)
简单:
{2, …, 6}
的所有2个子集,例如使用回溯。S
,请考虑H1 = S ⋃ {1}
,H2 = {1, …, 6} ∖ H1
A
中的H1
中的项目以及A
H2
中的项目
醇>
由于这会强制执行1 ∈ H1
,因此您不会获得[a,b,c][d,e,f]
,[d,e,f][a,b,c]
等重复。
由于套装没有订单,因此您不会获得[a,b,c][d,e,f]
,[b,a,c][f,d,e]
等重复。
答案 3 :(得分:0)
给定包含元素{1, …, 6}
的输入集,您需要 1。生成{2, …, 6}
和 2 计算的所有不同的3子集每个子集的交集(余数)与输入集:
function* subsets(input, length, start = 0) {
if (start >= input.length || length < 1) yield [new Set(), new Set(input)];
else {
for (let i = start; i <= input.length - length; ++i) {
let first = input[i];
for ([subsubset, remainder] of subsets(input, length - 1, i + 1)) {
subsubset.add(first);
remainder.delete(first);
yield [subsubset, remainder];
}
}
}
}
let input = ['a', 'b', 'c', 'd', 'e', 'f'];
for ([subset, remainder] of subsets(input, 3, 1)) {
console.log([...subset].join(''), [...remainder].join(''));
}
&#13;
这与@Oriol概述的算法非常相似。另请参阅@Dante详细解释为什么我们不将第一个元素包含到我们的3个子集中(为了防止双重,它包含在剩余部分中!)。
如果您的输入元素不是唯一的,则需要在输入的索引上运行上述算法而不是其值。
如果输入的大小超过6,则需要与剩余部分的所有子集合并:
for ([subset, remainder] of subsets(input, 3, 1)) {
for ([remainder_subset, _] of subsets([...remainder], 3)) {
console.log([...subset], [...remainder_subset]);
}
}
答案 4 :(得分:0)
我能想到的蛮力解决方案: -
第一个位置可以有6个选项中的任何一个。 第二个位置可以有五分之一 第三个可以有四分之一。
休息3将进入另一个列表。所以基本上需要做的是: -
继续生成所有3种大小的组合并将它们放在哈希映射中。生成新组合时,检查它是否存在于地图中。如果是,则跳过它,否则将其添加到地图中。有效的方法可能是存储组合的排序顺序。
希望这会有所帮助!!
答案 5 :(得分:-1)
尝试组合树和队列/堆栈数据结构来实现此类行为。 算法应该与树遍历看起来很简单。