给定一个字符串,求最长重复子串的长度。(最长重复字串之间可以有重叠的部分,如ababa,最长重复子串为aba,长度为3)
如果程序至多可以处理MAXN个字符,这些字符被存储在数组c中:
#define MAXN 5000000
char c[MAXN], *a[MAXN];
在读取输入时,首先初始化a,这样,每个元素就都指向输入字符串中的相应字符:
while (ch = getchar()) != EOF
a[n] = &c[n];
c[n++] = ch;
c[n] = 0 //将数组c中的最后一个元素设为空字符,以终止所有字符串。
这样,元素a[0]指向整个字符串,下一个元素指向以第二个字符开始的数组的后缀,等等。如若输入字符串为"banana",该数组将表示这些后缀:
a[0]:banana
a[1]:anana
a[2]:nana
a[3]:ana
a[4]:na
a[5]:a
由于数组a中的指针分别指向字符串中的每个后缀,所以将数组a命名为"后缀数组"
第二,对后缀数组进行快速排序,以将后缀相近的(变位词)子串集中在一起
qsort(a, n, sizeof(char*), pstrcmp)后
a[0]:a
a[1]:ana
a[2]:anana
a[3]:banana
a[4]:na
a[5]:nana
第三,使用以下comlen函数对数组进行扫描比较邻接元素,以找出最长重复的字符串:
for i = [0, n)
if comlen(a[i], a[i+1]) > maxlen
maxlen = comlen(a[i], a[i+1])
maxi = i
printf("%.*s/n", maxlen, a[maxi])
由于少了内层循环,只是多了一次排序,因此该算法的运行时间为O(n logn).
代码实现:
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
int cmp(const void* a , const void* b)
{
return strcmp(*(char**)a , *(char**)b);
}
int compare(char *a , char *b)
{
int i = 0;
while(*b && (*a++ == *b++))i++;
return i;
}
int main()
{
string str;
cin>>str;
int length = str.size();
cout<<str<<endl<<length<<endl;
char **ch = new char*[length];
int i;
for(i = 0 ; i < length ; i++)
ch[i] = &str[i];
qsort(ch , length , sizeof(char*) , cmp);
for(i = 0 ; i < length ; i++)
cout<<ch[i]<<endl;
int maxlen = -1;
for(i = 0 ; i < length-1 ; i++)
{
int len = compare(ch[i],ch[i+1]);
if(len > maxlen)
maxlen = len;
}
cout<<"最长重复字串的长度为:"<<maxlen<<endl;
return 0;
}