【问题标题】:How to find all the strings of the given conditions described?如何找到描述的给定条件的所有字符串?
【发布时间】:2013-12-06 10:55:50
【问题描述】:

问题:

  1. 给定一个整数 k。
  2. 有一个字符串10组成(例如'10110'), 在此处将其命名为二进制代码
  3. 二进制码的长度是2^k+k-1(例如给定k是2,所以 二进制码的长度是5)
  4. 如果二进制码的长度为k的子串在二进制码中只出现一次。

那么二进制码就是我们要找的。例如:

给定 k 为 2(例如匹配的二进制码的长度为 5。代码 "10011" 是匹配的,因为它的长度为 2 的子串是 "10","00","01","11",并且都出现在二进制代码只有一次。)。所有这些二进制代码都是“00110”“10011”“11001”“01100”

我正在寻找一种算法,以尽可能快地找到给定 k 的所有二进制代码

【问题讨论】:

  • 你的问题不清楚。你能重新表述你的问题陈述吗?还要在您的问题中包含您的尝试,而不是作为答案。
  • @AbhishekBansal 我已经编辑了我的问题并试图说明清楚,对你有什么帮助吗?
  • 您如何知道每个k 都有二进制代码?我的意思是符合所有要求(尤其是 4.)。
  • @Hynek-Pichi-Vychodil 如果没有二进制码符合条件,则返回None即可。其实我不知道每个k是否有二进制码

标签: string algorithm


【解决方案1】:

我们可以将二进制代码建模为长度k 的所有组合的排列。我们有2^k 组合,它们可以排列成(2^k)! 排列。这是相当多的代码,但要满足要求 3. 长度 2^k+k-1 表示每个长度组合的 k-1 后缀 k 必须是下一个组合的 k-1 前缀。当每个新组合添加一个新符号时,我们有第一个长度组合k2^k - 1 长度的新组合k。所以我们可以非常快地修剪所有这些(2^k)!

我们可以将长度k 的组合建模为二进制数。然后每个“代码”可以从这些数字之一开始,下一个数字必须具有来自前一个数字的k-1 位并添加一个新位 0 或 1。可以通过向左移动 1 并添加 0 或 1 来完成然后掩码为k 位。新号码只能在到目前为止没有使用过的情况下使用,所以我们必须记住使用过的号码。我们将生成长度为2^k 的序列,以满足上述要求。结果,我们将这些序列转换为相应的二进制代码。这意味着我们使用第一个数字中的所有位,并从所有下一个数字中添加最低位。或者我们可以使用所有数字的最高位并从最后一个添加所有位。

Erlang 中的结果代码:

-module(binary_code).

-export([gen/1]).

gen(K) ->
    N = (1 bsl K) - 1,
    gen(N, K, lists:seq(0, N)).

gen(Mask, K, L) ->
    [ [ $0 + B || <<B:1>> <= <<X:K>> ] ++ V
     || X <- L, V <- gen(Mask, Mask, X, [X]) ].

gen(_, 0, _, _) -> [[]];
gen(Mask, N, Prev, Prefix) ->
    P = (Prev bsl 1) band Mask,
    [ [$0 + (X band 1)|V] || X <- [P, P bor 1],
               not lists:member(X, Prefix),
               V <- gen(Mask, N-1, X, [X|Prefix])
              ].

结果:

44> binary_code:gen(1).
["01","10"]
45> binary_code:gen(2).
["00110","01100","10011","11001"]
46> binary_code:gen(3).
["0001011100","0001110100","0010111000","0011101000",
 "0100011101","0101110001","0111000101","0111010001",
 "1000101110","1000111010","1010001110","1011100010",
 "1100010111","1101000111","1110001011","1110100011"]
47> binary_code:gen(4).
["0000100110101111000","0000100111101011000",
 "0000101001101111000","0000101001111011000",
 "0000101100111101000","0000101101001111000",
 "0000101111001101000","0000101111010011000",
 "0000110010111101000","0000110100101111000",
 "0000110101111001000","0000110111100101000",
 "0000111100101101000","0000111101001011000",
 "0000111101011001000","0000111101100101000",
 "0001001101011110000","0001001111010110000",
 "0001010011011110000","0001010011110110000",
 "0001011001111010000","0001011010011110000",
 "0001011110011010000","0001011110100110000",
 "0001100101111010000","0001101001011110000",
 "0001101011110010000","0001101111001010000",
 [...]|...]
48> length(v(47)).
256
49> binary_code:gen(5).
["000001000110010100111010110111110000",
 "000001000110010100111011010111110000",
 "000001000110010100111110101101110000",
 "000001000110010100111110110101110000",
 "000001000110010101101001110111110000",
 "000001000110010101101001111101110000",
 "000001000110010101101110100111110000",
 "000001000110010101101111101001110000",
 "000001000110010101110110100111110000",
 "000001000110010101111101101001110000",
 "000001000110010110101001110111110000",
 "000001000110010110101001111101110000",
 "000001000110010110111010100111110000",
 "000001000110010110111110101001110000",
 "000001000110010111011010100111110000",
 "000001000110010111110110101001110000",
 "000001000110011101001010110111110000",
 "000001000110011101010010110111110000",
 "000001000110011101101001010111110000",
 "000001000110011101101010010111110000",
 "000001000110011111010010101101110000",
 "000001000110011111010100101101110000",
 "000001000110011111011010010101110000",
 "000001000110011111011010100101110000",
 "000001000110100101011001110111110000",
 "000001000110100101011001111101110000",
 "000001000110100101011100111110110000",
 "000001000110100101011101100111110000",
 [...]|...]
50> length(v(49)).     
65536

二进制代码的数量似乎是2^(2^(k-1))。它迅速升级。对于为更高的k 生成二进制代码,我建议使用C 或ASM。 (对于k=6,2^32 = 4,294,967,296。)

编辑

有我的 attempt 用 C 实现它,效果很好。

$ ./binary_code 1
01
10
$ ./binary_code 2
00110
01100
10011
11001
$ ./binary_code 3
0001011100
0001110100
0010111000
0011101000
0100011101
0101110001
0111000101
0111010001
1000101110
1000111010
1010001110
1011100010
1100010111
1101000111
1110001011
1110100011
$ time ./binary_code 4 | wc
    256     256    5120

real    0m0.003s
user    0m0.000s
sys     0m0.000s
$ time ./binary_code 5 | wc
  65536   65536 2424832

real    0m0.053s
user    0m0.088s
sys     0m0.000s
$ ./binary_code 6 | head -n 20
000000100001100010100011100100101100110100111101010111011011111100000
000000100001100010100011100100101100110100111101101110101011111100000
000000100001100010100011100100101100110100111111010101110110111100000
000000100001100010100011100100101100110100111111011011101010111100000
000000100001100010100011100100101100110101011101001111011011111100000
000000100001100010100011100100101100110101011101001111110110111100000
000000100001100010100011100100101100110101011101101111010011111100000
000000100001100010100011100100101100110101011101101111110100111100000
000000100001100010100011100100101100110101011110110111010011111100000
000000100001100010100011100100101100110101011111101101110100111100000
000000100001100010100011100100101100110110100111101010111011111100000
000000100001100010100011100100101100110110100111101110101011111100000
000000100001100010100011100100101100110110100111111010101110111100000
000000100001100010100011100100101100110110100111111011101010111100000
000000100001100010100011100100101100110110101011101001111011111100000
000000100001100010100011100100101100110110101011101001111110111100000
000000100001100010100011100100101100110110101011101111010011111100000
000000100001100010100011100100101100110110101011101111110100111100000
000000100001100010100011100100101100110110101011110111010011111100000
000000100001100010100011100100101100110110101011111101110100111100000

$ time ./binary_code 6 | wc
4294967296 4294967296 300647710720

real    123m18.854s
user    183m36.848s
sys     2m33.652s

$ time ./binary_code 6 > /dev/null

real    63m5.656s
user    62m50.808s
sys     0m11.072s

它可以为k=6 生成 75MB/s 的二进制代码。我也试过解决它without recursiongcc 必须在幕后做一些惊人的事情,因为非递归版本比我的第一个直接递归版本慢约 10%。

【讨论】:

  • 谢谢。我可以从你的描述中得到你的想法。但是由于我对Erlang不熟悉,请您在C/JAVA/Python/PHP中展示您的想法吗?
  • @Snowwolf:我添加了 C 代码。我认为它的速度可以通过更小的堆栈帧来提高(我不喜欢全局变量。)甚至完全避免递归,但这会困难得多。
  • @Snowwolf 我无法抗拒,所以我不递归地尝试了它,但它不起作用。
  • 而且堆栈帧的大小似乎也没有任何影响。只有分支预测很重要。
【解决方案2】:

我尝试通过以下方式解决问题:

  1. 找到所有可能的长度为 k 的子串并构建一个有向图 将这些字符串作为节点。
  2. 尝试在有向图中查找所有路径 它只会遍历所有节点一次。组成的字符串 路径中给定顺序的节点是与给定匹配的字符串 条件。

以下是我在 python 中的代码: 导入系统 导入类型

def find_path(s_map, slen):
    res = set()
    if (s_map):
        for i in s_map:
            used = list()
            used.append(i)
            res = find_sub(s_map, used, res, slen)

    return len(res),res

def find_sub(s_map, used, res, slen):
    if (set(used) != set(s_map)):
        for x in s_map[used[-1]]:
            if (x not in used):
                used.append(x)
                print used

                if (set(used) == set(s_map)):
                    sub = used[:-1]
                    s = ''
                    for i in sub:
                        s += i[0]
                    s += used[-1]
                    print s, len(s), len(s_map)
                    if (len(s) == slen):
                        print s
                        res.add(s)
                else:
                    find_sub(s_map, used, res, slen)
                used.remove(x)
            else:
                continue

    return res

def build_map(s_list):
    s_map = dict()

    for s in s_list:
        l = (s_list[0:])
        l.remove(s)
        s_map[s] = [i for i in l if s[1:] == i[:-1]]

    return s_map        

def binary_strings(k):
    if type(k) is types.IntType:
        return [(str(bin(i))[2:]).rjust(k, '0') for i in xrange(2 ** k) ]

def main():
    print find_path(build_map(binary_strings(2)), 2**2+2-1)
    print find_path(build_map(binary_strings(3)), 2**3+3-1)
    print find_path(build_map(binary_strings(4)), 2**4+4-1)

if __name__ == '__main__':
    sys(exit(main()))

【讨论】:

    猜你喜欢
    • 2012-12-28
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 2020-02-06
    相关资源
    最近更新 更多