Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 最长循环子串_String_Algorithm_Sorting - Fatal编程技术网

String 最长循环子串

String 最长循环子串,string,algorithm,sorting,String,Algorithm,Sorting,这是一个关于Jon Bentley的“编程珍珠”中描述的最长循环子串算法的问题。我记得,他们为输入字符串构建一个后缀数组,对后缀进行排序,然后扫描它们 看起来最昂贵的步骤是排序。如果我们使用比较排序,那么比较的数量是O(N*logN),其中N是输入字符串的大小。因为字符串比较是O(字符串长度),所以排序是O(N^2) 这有意义吗 因此,算法在空间中是O(N^2)和O(N)。它能做得更好吗?简单的排序会使后缀数组构造为O(n^2logn),而不是O(n^2) 然而,在O(n)中有构造后缀数组的方法

这是一个关于Jon Bentley的“编程珍珠”中描述的最长循环子串算法的问题。我记得,他们为输入字符串构建一个后缀数组,对后缀进行排序,然后扫描它们

看起来最昂贵的步骤是排序。如果我们使用比较排序,那么比较的数量是O(N*logN),其中N是输入字符串的大小。因为字符串比较是O(字符串长度),所以排序是O(N^2)

这有意义吗


因此,算法在空间中是O(N^2)和O(N)。它能做得更好吗?

简单的排序会使后缀数组构造为O(n^2logn),而不是O(n^2)

然而,在O(n)中有构造后缀数组的方法[一种简单的方法是构造后缀树并将其转换为后缀数组-后缀树构造为O(n)]


我不知道一个人是否可以用小于O(n)的空间来做。

虽然可以从后缀树构造后缀数组,但这没有什么意义。它将消除后缀数组的主要优点(除了一般的简单性):内存消耗小

有一种简单的方法可以对
O(n*logn)
time中的后缀数组进行排序。(由于这个原因,它经常被用于各种算法竞赛中,以替代复杂的后缀尝试)

基本思路如下。我们将分阶段对后缀进行排序,在阶段
i
i=0,1,2,3,
)中只考虑每个后缀的第一个
2^i
字符

按后缀的第一个字符排序很简单,对您来说应该没有问题。在这个(“第0个”)阶段之后,我们将有一个部分排序的后缀数组和另一个数组,其中包含将后缀划分为多个存储桶:每个存储桶包含具有相同第一个符号的后缀

现在,假设我们已经完成了阶段
i
,现在处理阶段
i+1
。我们需要比较属于同一个bucket的两个后缀
s(t)
s(q)
。(让
s(t)
成为原始字符串中从位置
t
开始的后缀。)
因为第一个<代码> 2 ^ i /代码>字符是相同的,所以我们只需要考虑下一个<代码> 2 ^ i /代码>字符(因此,总数将是代码>2 ^(i +1)< /代码>)。但是后缀
s(t)
没有它的第一个
2^i
符号是
s(t+2^i)
。因此,我们只需要根据它们的第一个
2^i
符号来比较
s(t+2^i)
s(q+2^i)
,我们已经从阶段
i
获得了这些信息

结束。第一次实现它可能有点棘手(这也是一个很好的练习),但这就是想法。请注意,从原始字符串读取实际字符的唯一时间是步骤
0
。然后,在步骤
i
,我们只使用步骤
i-1
的结果

编辑
详细介绍了这个想法。(IMHO表示,要理解it需要的细节要多得多,实现要比需要的复杂得多。)