e-KMP专题
(1)KMP和e-KMP会用
(2) 循环节
主要还是要会转换问题,问题的转换是不难的。
KMP 求S和T匹配的个数
int nextt[maxn]; void getNext(char T[]) { int len=strlen(T); int i = 1; nextt[1] = 0; int j = 0; while (i < len) { if (j == 0 || T[i] == T[j]) { ++i; ++j; nextt[i] = j; } else { j = nextt[j]; } } } int KMP(char S[], char T[], int next[], int pos) { //求T在S中pos位置后的位置 int i = pos; int j= 1; while ( i <= S.length() && j <= T.length()) { if(j == 0 || S[i] == T[j]) { ++i;++j; } else { j = next[j]; } } if(j > T.length()) return i - T.length(); else return 0; }
e-KMP可以一次性求出T对S的从每位开始比较的相同的个数,保存在extend里面
struct e_KMP { int Next[maxn], extend[maxn]; char *S, *T; int lenS, lenT; void init(char* S, char* T, int len1,int len2) {//第一个是被匹配的, 第二个是匹配的 this->S = S, this->T = T; lenS = len1 , lenT=len2; } void get_next() {//求模式串的next[] ta开始和从0开始时匹配的长度 Next[0] = lenT;//i=0的时候必然是这个 Next[1] = 0; while (Next[1] + 1 < lenT && T[Next[1]] == T[Next[1] + 1]) Next[1]++;//单独求i=1的时候 int k = 1, p = Next[1];//匹配的最远位置p与对应的起始点k for (int i = 2; i < lenT; i++) { if (p > i + Next[i - k] - 1) Next[i] = Next[i - k]; else { Next[i] = max(0, p - i + 1); while (i + Next[i] < lenT && T[i + Next[i]] == T[Next[i]]) Next[i]++; k = i, p = i + Next[i] - 1; } } } void work() {//从i开始时匹配的长度 get_next();extend[0] = 0;//单独求第一个 while (extend[0] < lenS && extend[0] < lenT && S[extend[0]] == T[extend[0]]) extend[0]++; int k = 0, p = extend[0] - 1; for (int i = 1; i < lenS; i++) { if (p > i + Next[i - k] - 1) extend[i] = Next[i - k]; else {//从p-i+1开始继续往后匹配 extend[i] = max(0, p - i + 1); while (i + extend[i] < lenS && extend[i] < lenT && S[i + extend[i]] == T[extend[i]]) extend[i]++; k = i, p = i + extend[i] - 1; } } } }ekmp;
主要就是要会用e-KMP,即将问题转换成字符串匹配的问题
--------------------
A 转换简单
B 转换简单
C 转换简单,就是难看懂题目
D e-KMP判断回文,即用str和str的逆序匹配
E KMP找循环节,e-KMP比较大小
好坑啊这题,超过了1e5,还会显示TLE, 绝了
KMP循环节: **i%(i-next(i))==0 , 说明字符串循环到 i-1 结束
循环节长度为: i - next[i]
循环次数为: i / ( i - next[i] )
F 转换简单
G KMP循环节
H 转换简单