找到字符串S的最短前缀T,使得S是T ^ n的前缀

时间:2012-04-23 11:47:32

标签: string algorithm prefix

我们使用的一般想法是使用贪婪算法检查字符串的剩余部分并进行比较。

这个想法不起作用,一般的想法可能是使用某种后缀树或KMP算法,但我尝试的一切都失败了。

有人可以帮忙吗?

P.S: T ^ n是前缀乘以n,因为n是字符串的长度,字符串字母介于[1..n]

之间

1 个答案:

答案 0 :(得分:3)

我会像Rabin karp algorithm一样使用滚动哈希。首先是双S,这样你就可以确定T ^ n是S * S的前缀。

接下来迭代T的长度。对于每个长度,您可以以对数复杂度计算T ^ n的哈希码(非常类似于二进制求幂)。在对S * S进行线性预计算之后,您可以在恒定时间内找到每个子串的哈希码(您需要一个包含其所有前缀的哈希的数组,还需要一个包含您正在使用的素数的幂的数组)用于散列)。因此,如果在O(log(n))中T ^ n == SUBSTRING(S ^ 2,n * LENGTH_OG(T)),你可以检查每个长度(这里你应该考虑一下如何计算哈希的时间每次迭代的t常数)。因此,提出的方法的总体复杂性将是O(LENGTH(S)* Log(LENGTH(S)))。

希望这有帮助。

编辑:我相信我找到了问题的线性解决方案。正如您所述,它基于KMP。计算字符串的失败函数后,请观察其值。例如:

string s = "abcdababcdababcdababcdababc";

值如下:

   a     b     c    d    a    b    a    b    c    d    a    b    a    b    c    d    a    b    a    b    c    d    a    b    a    b    c  
 -001  -001  -001  -001  000  001  000  001  002  003  004  005  006  007  008  009  010  011  012  013  014  015  016  017  018  019  020

看一下最终索引的价值。我相信如果你从S的长度中减去它然后再减去一个,你将获得最短重复子串的长度。在此示例中,您有27 - 20 - 1 = 6。在我上面显示的情况下更容易观察 - 当失败函数以0到20的值序列结束时。但实际上如果你有一些以20结尾的其他值,那么0到20将再次成为有效值失败功能只会跳过一些可能性。希望这是有道理的。该算法是线性的。