最长重复子串是指在一个字符串中找出最长的出现两次或两次以上的子串,例如abcdeabbcde,则bcde则是最长的重复子串。
最直观的解法是穷举所有的子串,和原串进行对比,从而选出最长的重复子串。
#include <stdio.h> #include <string.h> int commonLen(const char *str1, const char *str2){ int len = 0; if(str1 == NULL || str2 == NULL){ return 0; } while(*str1 && * str2 && *str1 == *str2){ str1++; str2++; len++; } return len; } int LRS(const char *str){ if(str == NULL){ return 0; } int i, j; int maxlen = 0, curlen = 0, maxindex = 0; int len = strlen(str); for(i = 0; i < len; i++){ for(j = i + 1; j < len; j++){ curlen = commonLen(str + i, str + j); if(curlen > maxlen){ maxlen = curlen; maxindex = i; } } } for(i = 0; i < maxlen; i++){ printf("%c", *(str + maxindex + i)); } return maxlen; } int main(){ char *str = "abcdeabbcde"; int len = LRS(str); printf("Max LRS = %d\n", len); }
这种算法的效率是O(N^3),效率不高,使用过KMP算法的同学会联想到这其实就是在求next数组的最大值问题,例如“abcdabcde”,它的next数组为:
-1 0 0 0 0 1 2 3 4 0
各个子串的next数组的最大值就是最长重复子串的长度。
#include <stdio.h> #include <string.h> #include <stdlib.h> int maxNext(const char *s, int _next[]){ _next[0] = -1; int i = 0; int j = -1; int max = 0; int len = strlen(s); while(i < len){ if(j == -1 || s[i] == s[j]){ i++; j++; _next[i] = j; if(j > max){ max = j; } }else{ j = _next[j]; } } return max; } int LRS_KMP(const char *str){ int len = strlen(str); int index = 0; int max = 0; int maxindex = 0; int *_next = (int *)malloc(len * sizeof(int)); int i; for(i = 0; i < len - 1; i++){ int curmax = maxNext(str + i, _next); if(curmax > max){ max = curmax; maxindex = i; } } for(i = 0; i < max; i++){ printf("%c", *(str + maxindex + i)); } return max; } int main(){ char *str = "abaabaaabaaaab"; int len = LRS_KMP(str); printf("Max LRS = %d\n", len); }