返回第i个位数组合

时间:2012-08-18 14:01:59

标签: algorithm bit-manipulation combinations

给定一个固定长度的位数组以及它包含的0和1的数量,我如何安排所有可能的组合,以便返回第i个组合花费的时间最少? 它们被退回的顺序并不重要。

以下是一个例子:

array length = 6
number of 0s = 4
number of 1s = 2

可能的组合(6!/ 4!/ 2!)     000011 000101 000110 001001 001010     001100 010001 010010 010100 011000     100001 100010 100100 101000 110000

问题     第一个组合= 000011     第5组合= 001010     第9组合= 010100

采用不同的安排,例如     100001 100010 100100 101000 110000     001100 010001 010010 010100 011000     000011 000101 000110 001001 001010

它将返回     第一组合= 100001     第5组合= 110000     第9组合= 010100

目前我正在使用O(n)算法测试每个位是否为1或0.问题是我需要处理许多非常长的数组(大约10000位),所以它仍然非常缓慢(缓存是不可能的)。我想知道您是否认为可能存在更快的算法。

谢谢

3 个答案:

答案 0 :(得分:1)

我不确定我是否理解这个问题,但是如果你只想要第i个组合而不产生其他组合,这里有一个可能的算法:

存在C(M,N)= M!/(N!(M-N)!)N位的组合,其设置为1,在位置M处具有最高位。

你想要第i个:你迭代地增加M直到C(M,N)> = i

while( C(M,N) < i ) M = M + 1

这将告诉你设置的最高位。 当然,您可以使用

迭代计算组合
C(M+1,N) = C(M,N)*(M+1)/(M+1-N)

一旦找到,你就有找到(i-C(M-1,N))N-1位组合的问题,所以你可以在N ...中应用递归 这是一个可能的变体,D = C(M + 1,N)-C(M,N),I = I-1,使其从零开始

SOL=0
I=I-1
while(N>0)
    M=N
    C=1
    D=1
    while(i>=D)
        i=i-D
        M=M+1
        D=N*C/(M-N)
        C=C+D
    SOL=SOL+(1<<(M-1))
    N=N-1
RETURN SOL

如果您有那么多位,这将需要大整数运算......

答案 1 :(得分:0)

如果排序无关紧要(它只需要保持一致),我认为最快的方法是组合(i)返回任何你想要的具有所需密度的东西第一次< / strong>使用参数i调用combination()。然后将该值存储在成员变量中(例如,具有值i作为键的散列映射以及作为其值返回的组合)。第二次组合(i)被调用,你只需在哈希映射中查找我,找出你之前返回的内容并再次返回它。

当然,当你为参数(i)返回组合时,你需要确保它不是你之前为其他论点返回的东西。

如果您要求返回的数字明显小于组合总数,则第一次调用组合(i)的简单实现是使用全0来设置正确长度的值,随机将这些位的num_ones设置为1,然后确保它不是你已经为不同的i值返回的那个。

答案 2 :(得分:0)

您的问题似乎受到二项式系数的限制。在您给出的示例中,问题可以翻译如下:

有6个项目可以一次选择2个。通过使用二项式系数,唯一组合的总数可以计算为N! /(K!(N - K)!,对于K = 2的情况简化为N(N-1)/ 2.插入6进N,我们得到15,这是你计算的相同组合数6!/ 4!/ 2! - 这似乎是计算我以前从未见过的二项式系数的另一种方法。我也尝试了其他组合,两个公式都生成了相同数量的组合。所以看起来像你的问题可以转化为二项式系数问题。

鉴于此,看起来您可能能够利用我编写的类来处理使用二项式系数的常用函数:

  1. 以任意N选择K到文件的格式输出所有K索引。 K索引可以用更具描述性的字符串或字母代替。这种方法使解决这类问题变得非常简单。

  2. 将K索引转换为已排序二项系数表中条目的正确索引。这种技术比依赖迭代的旧发布技术快得多。它通过使用Pascal三角形中固有的数学属性来实现。我的论文谈到了这一点。我相信我是第一个发现和发布这种技术的人,但我可能错了。

  3. 将已排序的二项系数表中的索引转换为相应的K索引。

  4. 使用Mark Dominus方法计算二项式系数,这样就不太可能溢出并使用更大的数字。

  5. 该类是用.NET C#编写的,它提供了一种通过使用通用列表来管理与问题相关的对象(如果有)的方法。此类的构造函数采用名为InitTable的bool值,当为true时,将创建一个通用列表来保存要管理的对象。如果此值为false,则不会创建表。不需要创建表来执行上述4种方法。提供访问者方法来访问该表。

  6. 有一个关联的测试类,它显示了如何使用该类及其方法。它已经过2个案例的广泛测试,并且没有已知的错误。

  7. 要阅读此课程并下载代码,请参阅Tablizing The Binomial Coeffieicent

    将此课程转换为您选择的语言应该不难。

    可能存在一些限制,因为您使用的是非常大的N,最终可能会产生比程序可以处理的更大的数字。如果K也可以很大,则尤其如此。现在,该类仅限于int的大小。但是,使用longs更新它应该不难。