k組み合わせの高速インデックス作成


11

少し前に取り組んでいた古い問題を再検討しています。

典型的なシナリオは、「8ビット整数内に3ビットが設定されている」、つまり00000111です。

ネストされたループによって、3セットのビットを持つすべての一意の組み合わせを(順番に)簡単に生成できます。私が興味を持っているのは、マッピングインデックス<->の組み合わせです。つまり、「00001011」が2番目の組み合わせ(またはゼロベースのインデックスでは値「1」)になります。

これまでのところ、すべての組み合わせを実行してテーブルに格納し、ルックアップインデックス->会話をO(1)操作にしました。もう一方の方向はO(ln(n))で、二分探索です。

ただし、欠点は、ドメインを増やすと、これが実行可能でないポイントまで、明らかにメモリに負荷がかかることです。

n番目の組み合わせまたは特定の組み合わせのインデックスを計算する簡単な方法は何ですか?組み合わせの順序はいいでしょうが、必須ではありません。



@MichaelTリンクは質問に対応していません-組み合わせの繰り返しは問題ではありません。これは、インデックスと組み合わせのマッピングについてです。「11001000」が与えられた場合、インデックス(または、もしそうなら列挙カウント)は何ですか?どのコードがインデックス1673に属しますか?
栄子

1
ああ、その場合はOEISが役に立つかもしれません。たとえば、シーケンス3,5,6,9,10,12,17,18は、2つの異なる2の累乗の合計を示します。これは、数学用語では「2ビットがオン」と言う別の方法です。さまざまな式は、n番目の値を計算するさまざまな方法を示しています。

1
8ビット整数には、格納するのが簡単なビットパターンの組み合わせが256個しかありません(そして、巧妙なコードよりもスペースを取りません)。あなたの目標/推定ビット数は何ですか?
9000

1
他の場所で掘り下げたように、これはコンビナトリアルナンバーシステムとして知られ、Gosper's HackはO(1)でそれを行うことができます。ロジックはHACKMEM 175で行われ、このブログ投稿で説明されていますオリジナルはかなり簡潔です)。

回答:


3

n番目の組み合わせを生成することを「ランク付け解除」アルゴリズムと呼びます。順列と組み合わせは、多くの場合、問題がパラメーター化される方法と同一視できることに注意してください。問題が何であるかを正確に知ることなく、正確な正しいアプローチを推奨することは難しく、実際、ほとんどの組み合わせの問題には、通常、いくつかの異なるランク付け/ランク付け解除アルゴリズムがあります。

良いリソースの1つは、KreherとStinsonによる「Combinatorial Algorithms」です。この本には、明確に説明された多くの優れたランキングおよびランキング解除アルゴリズムがあります。より高度なリソースがありますが、出発点として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;
}

これは順列のランク付け解除ですが、前述のように、多くの場合、ランク付け解除の組み合わせを同等の順列問題に変換できます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.