数据结构之最大重复子串
说明:
最大重复子串Longest repeat string,简称LRS,即在一个字符串中寻找最长的重复子串
例如"banana",则最大重复子串为"ana"
三种方法
方法1:暴力搜索法,复杂度O(N^2)
方法2:使用后缀数组的方法
方法3:利用KMP方法中的next数组
同时补充了个KMP的代码,与本题无关
// project1.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include<string.h> #include<algorithm> #define LENGTH 1000 //复杂度O(n^2) void max_substr(char str[]){ //寻找最大重复子串 int max=0,first_beg,second_beg; for(int i=0;i<strlen(str);i++){//第一个子串开始字符 for(int j=i+1;j<strlen(str);j++){//第二个子串开始字符 int cur_max=0; for(int k=i,l=j;k<strlen(str)&&l<strlen(str);k++,l++){ if(str[k]==str[l]) cur_max++; else break; } if(cur_max>max){ first_beg=i; second_beg=j; max=cur_max; } } } printf("Max Repeat Substring length=%d\n",max); } int compare(const void *p1,const void *p2){ //C++标准规定,const关键字放在类型或变量名之前等价的 //char * const cp; ( * 读成 pointer to ) cp is a const pointer to char //const char * p; p is a pointer to const char; //char const * p; 同上因为C++里面没有const*的运算符,所以const只能属于前面的类型 //排序没成功,因为p1和p2是指向字符的指针的指针 // return strcmp((char const*)p1,(const char*)p2); // printf("p1=0x%p\n",p1); // printf("(char const*)p1=0x%p\n",(char const*)p1); // printf("*(char const**)p1=0x%p\n",*(char const**)p1); // printf("**(char const**)p1=0x%c\n",**(char const**)p1); return strcmp(*(char** const)p1,*(const char**)p2); } //方法2:使用后缀数组 void LRS_suffix(char str[]){ int len=strlen(str); //指针数组,数组每个元素存的是char*的指针 char **suffix=new char*[LENGTH]; for(int i=0;i<len;i++) suffix[i]=str+i; //后缀数组按指向的内容排序 qsort(suffix,len,sizeof(char*),compare); int max=0; for(int i=0;i<len - 1;i++){ int cur_max=0; char *p1=suffix[i],*p2=suffix[i+1]; while(*p2 && *p1++==*p2++) cur_max++; if(cur_max>max) max=cur_max; } delete [] suffix; printf("Max Repeat Substring length=%d\n",max); } void KMP_getnext(char str[],int next[]){ next[0]=-1; int j=0,k=-1; while(j<=strlen(str)){ if(k==-1 || str[j]==str[k]) next[++j]=++k; else k=next[k]; } } //方法3:KMP法求最大重复子串. //最大重复子串相当于next数组的最大值max{next[i]} void KMP_substr(char str[]){ //求max{next[i]} int max=0; for(int i=0;i<strlen(str);i++){ int next[LENGTH]={0}; char *substr=(str+i); KMP_getnext(substr,next); for(int j=0;j<=strlen(substr);j++) if(next[j]>max) max=next[j]; } printf("Max Repeat Substring length=%d\n",max); } //KMP匹配,与本题无关 void KMP(char str[],char substr[]){ int next[LENGTH]; KMP_getnext(substr,next); int i=0;//主串位置 int j=0;//模式串位置 int pos=-1;//匹配的位置 int len1=strlen(str),len2=strlen(substr); while(i<len1 && j<len2){ if(j==-1 || str[i]==substr[j]){ i++;j++; } else j=next[j]; } if(j==strlen(substr)){//找到子串 pos=i-j; printf("Substring found! It begins at %d\n",pos); } else printf("Substrin not found!\n"); } int _tmain(int argc, _TCHAR* argv[]) { char str1[LENGTH]="banana"; char str2[LENGTH]="abcdefabcdeabcdabcaba"; char str3[LENGTH]="12345612343245656123"; char str4[LENGTH]="cdab"; char str5[LENGTH]="banaa"; char str6[LENGTH]="2456561"; max_substr(str1);max_substr(str2);max_substr(str3); LRS_suffix(str1);LRS_suffix(str2);LRS_suffix(str3); KMP_substr(str1);KMP_substr(str2);KMP_substr(str3); KMP(str2,str4);KMP(str1,str5);KMP(str3,str6); return 0; }