从1个列表

时间:2016-06-17 16:56:22

标签: javascript arrays algorithm combinatorics

我需要一个算法,它会从6个列表中生成2个3个字符的列表。例如,我有一个包含[a,b,c,d,e,f]的数组,我想创建[a,b,c][d,e,f]之类的组合。

我需要获得2次3个字符的所有可能组合。

约束

  • 两种组合可以是相同的。我的意思是我不能以不同的顺序将2个相同的3个字符组合在一起。因此,如果已生成[a,b,c][d,e,f],则我无法[b,a,c][f,d,e]作为另一种可能性或[f,d,e][b,a,c]

我理想情况下,如果算法是在javascript中,但我可以接受任何其他建议(我可以阅读代码,即使我不知道我最有可能的语言能够用我不知道的语言理解算法。我看了很多关于排列和组合的帖子和问题,但似乎没有一个我正在寻找的东西,我似乎无法弄清楚如何修改它们以适应我所做的事情。我正在寻找。

6 个答案:

答案 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;
&#13;
&#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)

简单:

  1. 迭代{2, …, 6}的所有2个子集,例如使用回溯。
  2. 对于每个子集S,请考虑H1 = S ⋃ {1}H2 = {1, …, 6} ∖ H1
  3. 当前组合包含A中的H1中的项目以及A
  4. 指定的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子集每个子集的交集(余数)与输入集:

&#13;
&#13;
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;
&#13;
&#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)

尝试组合树和队列/堆栈数据结构来实现此类行为。 算法应该与树遍历看起来很简单。