【问题标题】:search for long contiguous repeated substrings搜索长的连续重复子串
【发布时间】:2012-11-19 23:56:56
【问题描述】:

我有一串 0 和 1。将“连续双精度”定义为立即重复的子字符串。例如字符串“011101010101110”可以分解为“011 1010 1010 1110”,可以压缩为“011(1010)1110”。

有没有一种很好的算法来查找字符串中的所有连续双精度数?我能想到的最好的结果是字符串长度的二次方:

def all_contiguous_doubles(s):
    for j in range(len(s)):
        for i in range(j):
            if s[i:j] == s[j:2*j - i]:
                print "%s(%s)%s" % (s[:i], s[i:j], s[2*j - i:])

【问题讨论】:

  • 可以有很多个二次方。考虑字符串“111...111”
  • 在任何类型的字符串搜索中避免二次行为的方法是跳过前缀。但这在只有两个字符值的字符串中用处不大,因此它可能是一个糟糕的权衡。
  • 每个四位字符串至少包含一个双精度数,因此在任何长度为 n 的零和一字符串中总是至少有 n/4 双精度数。
  • 你可以让正则表达式引擎为你找到从某个位置开始的最长双精度的脏活:/(.+)$1/
  • @wye.bee 如果您愿意牺牲代码简单性来换取性能,请构建后缀树并选择最深的分支。

标签: python algorithm substring


【解决方案1】:

这里我介绍我的动态规划解决方案,它的时间复杂度为 O(n^2) 和 O(n^2)的空间复杂度,其中n是原始字符串的长度。

下面我递归地定义函数 dl(r,c)。 如果你把 dl(r,c) 做成一个表格并按正确的顺序填写,你将在 O(n^2) 内完成。

定义:

char(i) = i 位置的字符

substr(i) = 从位置 i 开始到原始字符串末尾的子字符串。

dl(r,c) = substr(r) 和 substr(c) 的公共非重叠前缀的长度。

dl(r,c)的递归定义:

由于 dl(r,c) 是对称的,我们只考虑 r

当 r == c 时,dl(r,c) = 0。 因为如果子字符串从同一点开始,它总是会重叠。

dl(r,c) = 0 当 char(r) != char(c)。 因为前缀不一样。

if char(r) == char(c),
    if dl(r+1,c+1) + 1 < c-r
        dl(r,c) = dl(r+1,c+1) + 1
    else
        dl(r,c) = dl(r+1,c+1)

拥有dl(r,c) == c-rdl(r,c) 的最大值将是您的答案。

【讨论】:

  • 空间复杂度可以通过精心管理降低到O(n)
【解决方案2】:

我会使用正则表达式 jan 提到 /(.+)$1/

这是一个简单的算法,否则可能会起作用:

创建一个函数

get_largest(string, i, j)

返回 i 和 j 之间最大的双精度数。

我会使用 min(20, (j-i)//2) 的 hash_size

现在假设你的 hash_size 是 20,找到长度为 20 的最不常见的子串以及它出现的所有位置。 (这可以通过哈希表快速完成)

现在假设找到的位置是 [10, 110, 320, 500, ..] 查看字符串 [10:110]、字符串 [110、320]、字符串 [320、500] 等。 如果这些子字符串中的任何一个多次出现,请找到这些子字符串的所有位置,并使用上述技术或其修改版本检查是否存在双精度数。

如果您仍然没有找到包含长度为 20 的最不频繁子字符串的双精度数,我们现在可以递归分治来搜索所有不包含最不频繁子字符串的最长子字符串。

希望在大多数情况下这应该很快。

【讨论】:

    【解决方案3】:

    如果压缩真的是你的最终目标:

    为什么没有一个大小为 16 的查找表,将字符串 "0000" "0001" 、 "1010" 等映射到它们各自的十六进制数字 '0-F' ?

    当您存储表示时:将二进制字符串转换为十六进制字符串序列?

    您可能还想在Grey Code 上查找。其中在二进制序列中,前一个数字和当前数字恰好相差 1 位。

    如果我们有表格中0-F的格雷码表示,那么:

    对于十六进制字符串中的字母:检查前一个或当前字母是否为“格雷码”顺序中的对应字母。如果是这样,您可以进一步压缩它。 (不同的位也可以在中间-某些情况必须正确处理')

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-08
      • 2020-10-03
      • 1970-01-01
      • 2017-05-30
      • 2019-01-12
      • 2014-07-20
      • 2020-11-29
      • 1970-01-01
      相关资源
      最近更新 更多