问题:给定一个文本文件作为输入,查找其中最长的重复子字符串。例如:“Ask not what your country can do for you, but what you can do for your country”中最长的重复字符串是“can do for you”,第二长的是“your country”。
我们使用一个叫做“后缀数组”的简单数据结构。它是一个字符指针数组,记为a。读取输入时,我们对a进行初始化,使得每个元素指向输入字符串中的相应字符:
const int MAXN = 5000000; char c[MAXN],*a[MAXN]; gets(c); while(c[n]!='\0') { a[n] = &c[n]; n++; }
a[0]:banana a[1]:anana a[2]:nana a[3]:ana a[4]:na a[5]:a数组a中指针所指的对象包含了字符串的每一个后缀,因此称a为“后缀数组”。
如果某个长字符串在数组c中出现两次,那么它将出现在不同的后缀中,因此我们对数组排序以寻找相同的后缀。“banana”数组排序为:
a[0]:a a[1]:ana a[2]:anana a[3]:banana a[4]:na a[5]:nana然后我们就可以扫描数组,通过比较相邻元素来找出最长的重复字符串,本例为“ana” 。
可以用qsort函数对后缀数组进行排序:
int pstrcmp(const void * a , const void *b) { const char *a_ = *(const char **)a; const char *b_ = *(const char **)b; return strcmp( a_ , b_ ) ; } qsort(a,n,sizeof(char *),pstrcmp);
使用comlen函数统计两个相邻单词共有的字母数:
int maxlen = 0 , maxi = 0; int templen = 0; for(int i=0;i<n-1;i++) { templen = comlen(a[i],a[i+1]); if( templen>maxlen ) { maxlen = templen ; maxi = i; } }
完整的程序为:
#include<iostream> #include<cstring> #include<string> #include<cstdlib> #include<algorithm> #include<iomanip> using namespace std; const int MAXN = 5000000; char c[MAXN],*a[MAXN]; //其中a为后缀数组 int pstrcmp(const void * a , const void *b) { const char *a_ = *(const char **)a; const char *b_ = *(const char **)b; return strcmp( a_ , b_ ) ; } int comlen(char* p ,char* q) { int i = 0; while( *p && (*p++ == *q++) ) { i++; } return i; } int main() { int n = 0; /* * 获取字符串c,并且给后缀数组a赋值 */ gets(c); while(c[n]!='\0') { a[n] = &c[n]; n++; } c[n] = 0; //对后缀数组进行排序,实际上就是对指针数组a进行排序 qsort(a,n,sizeof(char *),pstrcmp); for(int i=0;i<n;i++) { cout<<a[i]<<endl; } //扫描数组,使用comlen函数统计两个相邻单词共有的字母数 int maxlen = 0 , maxi = 0; int templen = 0; for(int i=0;i<n-1;i++) { templen = comlen(a[i],a[i+1]); if( templen>maxlen ) { maxlen = templen ; maxi = i; } } printf("\n%.*s\n",maxlen,a[maxi]); //printf语句使用"*" 精度输入字符串中的maxlen个字符 cout.write(a[maxi],maxlen)<<endl; //和上一句起到相同的效果 system("pause"); return 0; }
#include<iostream> #include<cstring> #include<string> #include<cstdlib> #include<algorithm> #include<iomanip> #include<stdio.h> using namespace std; const int MAXN = 100010; char source[MAXN*2],append[MAXN]; char *a[MAXN*2]; inline int pstrcmp(const void * a , const void *b) { const char *a_ = *(const char **)a; const char *b_ = *(const char **)b; return strcmp( a_ , b_ ) ; } inline int comlen(char* p ,char* q,int maxlen) { if(strncmp(p,q,maxlen) != 0) { return 0; } int i = maxlen; p += maxlen; q += maxlen; while( *p && *q && (*p++ == *q++) ) { i++; } return i; } int main() { int i; scanf("%s",source); scanf("%s",append); source[strlen(source)] = '$'; strcat(source,append); // cout<<source<<endl; for(i=0;i<strlen(source);i++) { a[i] = &source[i]; } // for(i=0;i<strlen(source);i++) // { // cout<<a[i]<<endl; // } qsort(a,strlen(source),sizeof(char *),pstrcmp); // for(int i=0;i<strlen(source);i++) // { // cout<<a[i]<<endl; // } int maxlen = 0 , maxi = 0; int templen = 0; int append_len = strlen(append); for(int i=0;i<strlen(source)-1;i++) { if( ( strlen(a[i])<=append_len&&strlen(a[i+1])>append_len+1) || ( strlen(a[i])>append_len+1&&strlen(a[i+1])<=append_len) ) { if( strlen(a[i])>maxlen || strlen(a[i+1])>maxlen ) { templen = comlen(a[i],a[i+1],maxlen); if( templen>maxlen ) { maxlen = templen ; maxi = i; } } else { continue; } } } //printf("\n%.*s\n",maxlen,a[maxi]); //cout.write(a[maxi],maxlen)<<endl; cout<<maxlen<<endl; system("pause"); return 0; }
12302529 | niuliguo | 2774 | Time Limit Exceeded | G++ | 2094B | 2013-11-15 16:33:03 |
未完待续。。。
注明出处:http://blog.csdn.net/lavorange/article/details/16857419