k组合的快速索引


12

我正在重新审视我前一段时间正在研究的一个老问题。

典型的场景是“在8位整数内设置3位”,即00000111。

通过嵌套循环可以轻松地(按顺序)生成具有3个置位的所有唯一组合。我感兴趣的是映射索引<->组合,即“ 00001011”将是第二个组合(或从零开始的索引中的值“ 1”)。

到目前为止,我浏览了所有组合并将它们存储在表中,从而使查找索引->对话成为O(1)操作。另一个方向是对分搜索的O(ln(n))。

但是,不利的一面是,如果我们增加域的范围,这显然会占用大量内存,直到不可行的程度。

计算第n个组合或给定组合的索引的简单方法是什么?组合顺序会很好,但不是强制性的。



@MichaelT您的链接没有解决问题-遍历组合不是问题。这是关于映射索引和组合。给定“ 11001000”,索引是多少(或者,如果要的话,枚举计数)是多少?什么代码属于索引1673?
Eiko 2015年

1
嗯,在这种情况下,您可能会发现OEIS很有用。例如,序列3,5,6,9,10,12,17,18给我们两个的两个不同幂的和,这是数学术语中“两个位在”的另一种说法。那里的各种公式显示了计算nth值的各种方法。

1
8位整数只有256个任意模式的组合,这些组合很难存储(并且比任何巧妙的代码占用更少的空间)。您的目标/估计位数是多少?
9000

1
正如在其他地方挖掘的那样,这被称为组合数字系统,Gosper的Hack可以在O(1)中做到这一点。该逻辑是在HACKMEM 175中完成的,并在此博客文章中进行了解释(原文非常简洁)。

Answers:


4

生成第n个组合称为“不排序”算法。请注意,排列和组合通常可以等同于问题的参数化方式。在不确切知道问题是什么的情况下,很难推荐正确正确的方法,并且实际上,对于大多数组合问题,通常可能有几种不同的排序/不排序算法。

一种很好的资源是Kreher和Stinson的“组合算法”。本书有许多很好的排名和排名算法,这些算法已经清楚地说明了。有更多高级资源,但是我建议您以Kreher作为起点。作为取消排序算法的示例,请考虑以下内容:

/** PKSUL : permutation given its rank, the slots and the total number of items
 *  A combinatorial ranking is number of the permutation when sorted in lexicographical order
 *  Example:  given the set { 1, 2, 3, 4 } the ctItems is 4, if the slot count is 3 we have:
 *     1: 123    7: 213   13: 312   19: 412
 *     2: 124    8: 214   14: 314   20: 413
 *     3: 132    9: 231   15: 321   21: 421
 *     4: 134   10: 234   16: 324   22: 423
 *     5: 142   11: 241   17: 341   23: 431
 *     6: 143   12: 243   18: 342   24: 432
 *  From this we can see that the rank of { 2, 4, 1 } is 11, for example. To unrank the value of 11:
 *       unrank( 11 ) = { 11 % (slots - digit_place)!, unrank( remainder ) }
 * @param rank           the one-based rank of the permutation
 * @param ctItems        the total number of items in the set
 * @param ctSlots        the number of slots into which the permuations are generated
 * @param zOneBased      whether the permutation array is one-based or zero-based
 * @return               zero- or one-based array containing the permutation out of the set { ctItems, 1,...,ctItems }
 */
public static int[] pksul( final int rank, final int ctItems, final int ctSlots, boolean zOneBased ){
    if( ctSlots <= 0 || ctItems <= 0 || rank <= 0 ) return null;
    long iFactorial = factorial_long( ctItems - 1 ) / factorial_long( ctItems - ctSlots );
    int lenPermutation = zOneBased ? ctSlots + 1 : ctSlots;
    int[] permutation = new int[ lenPermutation ];
    int[] listItemsRemaining = new int[ ctItems + 1 ];
    for( int xItem = 1; xItem <= ctItems; xItem++ ) listItemsRemaining[xItem] = xItem; 
    int iRemainder = rank - 1;
    int xSlot = 1;
    while( true ){
        int iOrder = (int)( iRemainder / iFactorial ) + 1;
        iRemainder = (int)( iRemainder % iFactorial );
        int iPlaceValue = listItemsRemaining[ iOrder ];
        if( zOneBased ){
            permutation[xSlot] = iPlaceValue;
        } else {
            permutation[xSlot - 1] = iPlaceValue;
        }
        for( int xItem = iOrder; xItem < ctItems; xItem++ ) listItemsRemaining[xItem] = listItemsRemaining[xItem + 1]; // shift remaining items to the left
        if( xSlot == ctSlots ) break;
        iFactorial /= ( ctItems - xSlot );
        xSlot++;
    }
    if( zOneBased ) permutation[0] = ctSlots;
    return permutation;
}

这是置换排序,但是如上所述,在许多情况下,您可以将组合排序转换为等效的置换问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.