高效算法,在n个元素的数组中打印长度为k的所有子集

时间:2014-07-31 07:35:43

标签: arrays algorithm set combinations

这是一个非常经典的问题,我发现的大多数解决方案都使用递归方法,如this。由于存在Cn,k组合,我想知道是否存在可以在O(n * Cn,k)时间内打印所有组合的算法。我认为链接中给出的答案比这要花费更多时间。此外,是否有一种算法可以打印结果而不使用额外的空间(我的意思是,没有额外的空间依赖于n和k.O(1)肯定没问题)?

感谢。

2 个答案:

答案 0 :(得分:1)

链接的算法尽可能快地为您提供所有排列 - O(n!/k!) - 这很慢,因为存在指数级的排列。

要在O(Cn,k)时间内获得所有组合,您可以在其他问题的答案中使用其中一种算法:Algorithm to return all combinations of k elements from n

答案 1 :(得分:1)

只需从Windows命令行(cscript test.js)测试一个简单的javascript代码。

这只是带进位的总和,其中“数字”是集合中元素的位置。

没有递归,只需要存储set元素和数组来保存当前子集。

// define the initial set
var set = 'abcdefg'.split('');
var setLength = set.length;

// define the subset length and initialize the first subset
var subsetLength = 5;
var aSubset = new Array(subsetLength+1);

var i;
    for( i = 0 ; i < subsetLength ; i++ ) aSubset[i]=i;

// place a guard at the end
    aSubset[subsetLength] = setLength;

// generate each of the posible subsets 
// This is just a sum with carry where the value of each of the "digits" 
// is in the range [i..subset[i+1])
var r = 0, start = 0;
    do {
        // print the subset
        for( i = 0 ; i < subsetLength ; i++ ) {
            WScript.StdOut.Write( set[aSubset[i]] );
        };
        WScript.StdOut.WriteLine('');

        // calculate the next subset
        for( i = start, r = 1 ; i < subsetLength ; i++ ) {
            aSubset[i]++;
            if (aSubset[i] < aSubset[i+1]) { 
                start = ( i==0 ? 0 : i-1 ); 
                r = 0; 
                break; 
            } else { 
                aSubset[i] = i 
            };
        };
    } while (r == 0);