K个项目可以在N个插槽中排列的所有可能方式

时间:2012-07-06 10:57:33

标签: java algorithm combinations

我正在寻找一种算法来查找K值与n项的所有组合。

示例:

K值是[R,B]& N是2所以我得到{RR,RB,BR,BB} 2 * 2 = 4种方式

K值是[R,B]& N是3所以我得到{RRR,RRB,RBB,RBR,BRR,BRB,BBR,BBB} 2 * 2 * 2 = 8种方式

我需要找出通用算法来找到K个项目可以在N个槽中排列的所有可能方式。 (允许重复)

另一个例子是:

K值是[R,G,B]& N是5所以我需要找到3 ^ 5 = 81种组合。

2 个答案:

答案 0 :(得分:2)

这个问题非常适合递归解决方案。

通常情况下的解决方案是通过采用N - 1的解决方案,然后将每个集合的元素依次添加到结果中来形成的。在伪代码中:

f(options, 0) = []
f(options, n) = options foreach o => o ++ f(options, n-1)

这可以在Java中递归实现,但是对于中等大小的n值,你会遇到堆栈溢出错误;我还怀疑JIT编译器在优化递归算法方面效率较低,因此性能会受到影响。

但是,递归算法总是可以转换为循环等价物。在这种情况下,它可能看起来像:

List<String> results = new ArrayList<String>();
results.add(""); // Seed it for the base case n=0
for (int i = 0; i < n; i ++) {
    List<String> previousResults = results;
    results = new ArrayList<String>();
    for (String s : options) {
       for (String base : previousResults) {
           results.add(s + base);
       }
    }
}
return results;

这与(我希望!)类似于递归方法 - 在每次迭代时它将当前进度(即n-1的结果)“保存”到previousResults,然后迭代选项反过来,得到的结果是将它们添加到之前的结果中。

通过任何自动递归到迭代算法传递递归解决方案的效果会很有趣,并将可读性和性能与这个手工创建的算法进行比较。这留给读者练习。

答案 1 :(得分:1)

我将在基数k中使用N位的计数器。 例如:k = 3,n = 5

(0,0,0,0,0)
(0,0,0,0,1),
....
(2,2,2,2,2)

实现这样的计数器很简单,只需保持大小为n + 1的数组,首先将所有元素设置为零,每次增加最新元素,如果它将超过k-1,则增加下一个邻居(直到邻居超过K-1)。当n + 1个元素设置为1时,动作终止。

如果您尝试过但不能这样做,请通过评论告诉它。