生成具有所有唯一 k 位子序列的所有 n 位序列。

Generate all n - bit sequences with all unique k-bit subsequences.

我发现了这个问题:

Consider sequences of 36 bits. Each such sequence has 32 5 - bit sequences consisting of adjacent bits. For example, the sequence 1101011… contains the 5 - bit sequences 11010,10101,01011,…. Write a program that prints all 36 - bit sequences with the two properties: 1.The first 5 bits of the sequence are 00000. 2. No two 5 - bit subsequences are the same.

于是我归纳出所有n位序列,其中k位唯一子序列满足上述要求。然而,我能想到的唯一方法是使用残酷的强制搜索:生成前 k 位为零的 n 位序列的所有排列,然后对于每个序列,检查所有 k 位子序列是否唯一。这显然不是一种非常有效的方法。我想知道有没有更好的方法来解决这个问题?

谢谢。

我记得在我的编程面试问题书中看到过这个确切的问题。这是他们的解决方案:

希望对您有所帮助。干杯。

最简单的方法似乎是回溯方法。您可以跟踪使用平面数组看到的 5 位序列。在每一位,尝试添加 0 -- counter = (counter & 0x0f) << 1 并检查您之前是否见过它,然后执行 counter = counter | 1 并尝试该路径。

可能有更高效的算法可以更快地修剪搜索 space。这似乎与 https://en.wikipedia.org/wiki/De_Bruijn_sequence 有关。我不确定,但我相信它实际上是等价的;也就是说,序列的最后五位数字必须是 10000,使其循环。

编辑:这是一些 C 代码。由于递归,效率低于 space,但很简单。最糟糕的是掩码管理。看来我对 De Bruijn 序列的看法是正确的;这会找到所有 2048 个。

#include <stdio.h>
#include <stdlib.h>

char *binprint(int val) {
    static char res[33];
    int i;
    res[32] = 0;
    for (i = 0; i < 32; i++) {
        res[31 - i] = (val & 1) + '0';
        val = val >> 1;
    }
    return res;
}

void checkPoint(int mask, int counter) {
    // Get the appropriate bit in the mask
    int idxmask = 1 << (counter & 0x1f);

    // Abort if we've seen this suffix before
    if (mask & idxmask) {
        return;
    }

    // Update the mask
    mask = mask | idxmask;

    // We're done if we've hit all 32
    if (mask == 0xffffffff) {
        printf("%10u 0000%s\n", counter, binprint(counter));
        return;
    }

    checkPoint(mask, counter << 1);
    checkPoint(mask, (counter << 1) | 1);
}

void main(int argc, char *argv[]) {
    checkPoint(0, 0);
}