今天面试被一道没见过的题,完全整闷了。求一段字符串的最长重复子串。后来网上看看博客,竟然可以用KMP写,为自己的无知感到羞愧。好吧,我来学习一下如何用KMP方法解决这样的问题,关键是next的特性来解决这个问题。
#include <iostream> #include <cstring> using namespace std; int Get_next(char *p, int nextval[]) { int j = -1; nextval[0] = -1; int len = strlen(p); int i = 0; int maxlen = 0; while(i < len) { if(j == -1 || p[i] == p[j]) { i++; j++; nextval[i] = j; if(j > maxlen) //求其中重复最大的字符串的个数,也就是与前面最前串的重复数 maxlen = j; } else j = nextval[j]; } return maxlen; } int main() { char s[100]; cin >> s; int maxlen = 0;//最大串的个数 int nextMax; //Get_next函数得到的最大值 int i; int maxIndex; int len = strlen(s); for(i = 0; i < len-1; i++) { int *next = new int[len - i]; nextMax = Get_next(s + i, next); if(nextMax > maxlen) { maxIndex = i; maxlen = nextMax; } } cout << "输出最长重复子串:" << endl; for(i = 0; i < maxlen; i++) cout << s[i + maxIndex]; cout << endl; }
使用KMP的特性来解决这道题,时间复杂度有点高啊。
事情总有解决的方法,所以就有了后缀数组这一数据结构来解决这个方法。对一个字符串生成相应的后缀数组后,再排序,排序后依次检测相邻的两个字符串的开头部分。
#include <iostream> #include <cstring> #include <stdio.h> #include <algorithm> using namespace std; #define MAXLEN 10000 char str[MAXLEN], *arr[MAXLEN]; int CalLen(const char *str1, const char *str2) { int len = 0; while(*str1 && (*str1++ == *str2++)) len++; return len; } int pStrCmp(const void *str1, const void *str2) { return strcmp(*(const char **)str1, *(const char **)str2); } int main() { char ch; int n = 0; int maxlen = 0, maxIndex = 0; int temp; while((ch = getchar()) != ' ') { arr[n] = &str[n]; str[n++] = ch; } str[n] = '