最长的非重叠子串

时间:2009-08-24 17:39:07

标签: algorithm string substring programming-pearls

我想知道是否有人知道最长重复非重叠子串的(最佳?)算法。

例如,在字符串

ABADZEDGBADEZ

最长的反复出现是“不好”。顺便提一下,如果没有这样的结果,算法应该警告这样的事情已经发生。我猜这是涉及后缀树。

我确信这必须已存在于某个地方。谢谢你的帮助!

4 个答案:

答案 0 :(得分:4)

由于您将此应用于音乐,您可能不会寻找100%匹配;从主题的一个实例到另一个实例将存在预期的差异。你可能会尝试查找基因序列分析算法 - 那里有很多这样的东西。尝试BLAST或其他对齐算法。

您还可以尝试WinEPI系列算法,以及此特定结果集的各种前缀树实现(这些结果允许子字符串中的间隙;例如,ABCID和AFBCD都包含ABCD)。我实际上有一篇关于算法的文章,如果你感兴趣的话可能值得一看;我需要获得发行授权,所以请告诉我。

请注意,对于大型数据集而言,这实际上是一个非常复杂的主题(为了有效)。

资料来源:关于可比(主题检测)主题的一两年研究。

答案 1 :(得分:4)

Suffix array是解决该问题的良好数据结构。

Jon Bentley在Programming Pearls中解决了这个问题。

答案 2 :(得分:1)

一个简单的算法就是这样做:

  • 创建表示字符串切片的数据结构;实施适合语言的比较/排序
  • 创建以[first-character,last-character],[second-character,last-character],[last-character,last-character]
  • 开头的每个字符串切片的列表
  • 对此列表进行排序 - O(n log n)
  • 这会将所有带有公共前缀的字符串切片组合在一起。然后,您可以遍历列表,比较每一对以查看它们在开始时共享的字符数,如果它大于您的最大值,则记下它并将其设置为新的最大值

(正如刚发布的另一个回复所示,我在这里描述了一个后缀数组。)

答案 3 :(得分:0)

好的,这是一个疯狂的想法。

创建一个函数,确定在O(n)中是否存在长度为k的重复子字符串(其中n是文本的长度)。这可以通过使用滚动哈希(参见维基百科Rabin-Karp String Matching Algorithm)来生成线性时间内的所有n个哈希并使用哈希表/ BST(或地图或字典或您的语言调用它)来存储相应的哈希值子串位置。在将当前哈希插入数据结构之前,我们先检查是否已经看过它。如果之前已经看过,我们只需查找生成此哈希的索引,并查看相应的子字符串是否为非重叠匹配。

既然我们可以在O(n)时间内找到一个k长度的子串,我们只需运行一个二进制搜索来找到最大的k,我们可以使用我们的函数找到一个非重叠的子串匹配。

Python中的代码如下

A=23
MOD=10007 # use a random value in the real world

def hsh(text):
    return sum([ord(c)*A**(len(text)-i-1) for i,c in enumerate(text)])%MOD

def k_substring(text, k):
    substrings={}
    cur=hsh(text[:k])
    pwr=(A**(k-1))%MOD
    substrings[cur]=[0]
    for i in xrange(k,len(text)):
        to_remove=(ord(text[i-k])*pwr)%MOD
        to_add=ord(text[i])
        cur-=to_remove
        if cur<0:
            cur+=MOD
        cur=(cur*A)%MOD
        cur=(cur+to_add)%MOD
        if cur in substrings:
            lst=substrings[cur]
            for index in lst:
                if index+k<=i-k+1 and text[index:index+k]==text[i-k+1:i+1]:
                    return index
            lst.append(i-k+1)
        else:
            substrings[cur]=[i-k+1]
    return -1

def longest_substring(text):
    hi,lo=len(text),0
    while hi>lo:
        mid=(hi+lo+1)>>1
        if k_substring(text,mid)==-1:
            hi=mid-1
        else:
            lo=mid
    index=k_substring(text,lo)
    return text[index:index+lo]

(对不起,如果不清楚的话。现在是早上6:30,我真的需要回去睡觉:))