使用KMP寻找最长的前缀的方法,比一般的暴力法有快了很多。
本题一般的暴力法需要的是O(m*n*n*n),其中m是有多少字符串,而n是字符串长度,而使用KMP就可以把时间效率提高到O(m*n*n),减少了一个n,提高了一个档次啦。
速度快很多。
准确来说应该是利用KMP寻找一个字符串A,在另一个字符串B任意位置出现的A的最长的前缀字符串。
理解好KMP的next table就好办了。每次查找到相等字符的时候,保存好最长的前缀。
注意本题的条件:选取最前的字典顺序输出。老害我错的条件。
#include <stdio.h> #include <string.h> #include <stdlib.h> const int MAX_N = 61; const int MAX_M = 11; const int ALP_LEN = 4; const int SIGNIFICANT = 3; char dict[MAX_M][MAX_N]; int kmpTable[MAX_N]; int n; inline int max(int a, int b) { return a > b ? a : b; } inline int min(int a, int b) { return a < b ? a : b; } int longestPrefix(char *chs, int len) { memset(kmpTable, 0, sizeof(int)*len); for (int i = 1, j = 0; i < len; i++) { if (chs[i] == chs[j]) kmpTable[i] = ++j; else if (j > 0) { j = kmpTable[j-1]; i--; } } int L = MAX_N - 1; for (int i = 1; i < n; i++) { int tmpAns = 0; for (int k = 0, j = 0; k < L && j < len; k++) { if (chs[j] == dict[i][k]) { ++j; tmpAns = max(tmpAns, j); } else if (j > 0) { j = kmpTable[j-1]; k--; } } len = min(len, tmpAns);//optimize } return len; } int main() { int T; scanf("%d", &T); while (T--) { scanf("%d", &n); getchar(); // get rid of '\n' for (int i = 0; i < n; i++) { gets(dict[i]); } int len = MAX_N - 1; int maxLen = 0; int pos = 0; char res[MAX_N] = {'\0'}; char subStr[MAX_N] = {'\0'}; for (int i = 0; i < len; i++)//search every start position { int tmpLen = longestPrefix(dict[0]+i, len-i); if (tmpLen >= maxLen) { if (tmpLen > maxLen) { maxLen = tmpLen; pos = i; } else//irritating alphabetic order { strncpy(res, dict[0]+pos, maxLen); strncpy(subStr, dict[0]+i, tmpLen); if (strcmp(res, subStr)) { maxLen = tmpLen; pos = i; } } } } if (maxLen < SIGNIFICANT) { puts("no significant commonalities"); } else { strncpy(res, dict[0]+pos, maxLen); printf("%s\n", res); } } return 0; }
POJ 3080 Blue Jeans KMP解法,布布扣,bubuko.com
原文:http://blog.csdn.net/kenden23/article/details/38357727