KMP算法
KMP算法求出ex[i]数组,ex[i]数组表示主串S中以第i个字符(也即S[i-1]位置)为尾字符的后缀与模式串T的前缀的最长公共部分。
KMP模板中,字符都是从下标0开始存放的,直到m-1位置。假设有两个串S和T,其中T为模板串,S为主串。KMP其实本质是用来看S中每个i位置的后缀最多能与T的多长的前缀匹配的算法。即前缀匹配后缀的算法。进行模式串匹配只是KMP的一个附加结果。
其实求得的f[i]==x表示i位置的模式串T的0到i-1字符的后缀能与模式串T的0到x-1字符匹配。即当T[i]与S[j]不匹配的时候,就取用T[f[i]]==T[x]与S[j]匹配看看是否能匹配。
MP与KMP模板如下:
/*************************MP模板****************************/
char T[1000];//待匹配串
char P[100];//模板串
//失配指针,记住这里f要比P多一位
//因为P到m-1即可,但是f还要计算出m的失配指针
int f[101];
void find(char *T, char *P, int *f) //找到所有匹配点
{
int n = strlen(T);
int m = strlen(P);
int j = 0;
for(int i = 0; i < n; i++)
{
while(j && T[i] != P[j]) j = f[j];
if(T[i] == P[j]) j++;
if(j == m) printf("%d\n", i - m + 1);//就算j到m了,也用f[m]继续匹配
}
}
void getFail(char *P, int *f)
{
int m = strlen(P);
f[0] = f[1] = 0;
for(int i = 1; i < m; i++)//虽然字符串是0到m-1,但是要求出f[m]的值
{
int j = f[i];
while(j && P[i] != P[j]) j = f[j];
f[i + 1] = P[i] == P[j] ? j + 1 : 0;
}
}
/*************************MP模板****************************/
/*************************KMP模板****************************/
char T[1000];//待匹配串
char P[100];//模板串
int f[101];//优化后的失配指针,记住这里f要比P多一位,因为P到m-1即可,但是f还要计算出m的失配指针
int f2[101];//f2用来保存KM指针,是为优化f的失配指针,f保存的是优化之后的失配指针
void find(char *T, char *P, int *f) //找到所有匹配点
{
int n = strlen(T);
int m = strlen(P);
int j = 0;
for(int i = 0; i < n; i++)
{
while(j && T[i] != P[j]) j = f[j];
if(T[i] == P[j]) j++;
if(j == m) printf("%d\n", i - m + 1);
}
}
void getFail(char *P, int *f)
{
int m = strlen(P);
f[0] = f[1] = 0;
f2[0]=f2[1]=0;
for(int i = 1; i < m; i++)
{
int j = f2[i];
while(j && P[i] != P[j] ) j = f2[j];
f2[i+1] = f[i + 1] = (P[i] == P[j]) ? j + 1 : 0;
//既然i+1的失配位置指向j+1,但是P[i+1]和P[j+1]的内容是相同的
//所以就算指针从i+1跳到j+1去,还是不能匹配,所以f[i+1]直接=f[j+1]
if(f[i+1]==j+1 && P[i+1]==P[j+1]) f[i+1]=f[j+1];
}
}
/*************************KMP模板****************************/
KMP模板题
POJ 3461Oulipo(KMP:统计一个串出现的次数):KMP模板题。解题报告!
HDU 1711Number Sequence(KMP:找模板第一次出现的位置):KMP模板题。解题报告!
HDU 3336Count the string(KMP:串前缀匹配自身+DP):简单的前缀匹配+DP问题。解题报告!
POJ3080 Blue Jeans(KMP:最长连续公共子序列):求多个字符串的最长公共连续子串,如果存在多个长度相同的就输出字典序最小的那个。解题报告!
POJ3450 Corporate Identity(KMP:最长连续公共子序列):类似于上一题。解题报告!
HDU2087剪花布条(KMP:贪心):需要贪心的从左到右有考虑。解题报告!
HDU2203亲和串(KMP:循环移位):给你串T和串P问你串P是否能和T循环移K位后的串匹配。解题报告!
HDU1867 A + B for you again(KMP:后缀与前缀):字符串合并。解题报告!
KMP前缀与后缀
HDU 2594Simpsons’ HiddenTalents(KMP:后缀与前缀):KMP的思想。解题报告!
POJ 2752Seek the Name, Seekthe Fame(KMP:后缀与前缀):找出所有前缀与后缀匹配的长度。解题报告!
求字符串最短循环节
UVA 1328Period(KMP:最短循环节):如何求字符串的循环节?解题报告!
POJ 2406Power Strings(KMP:找串循环节):求出最小循环节个数。解题报告!
HDU 3746Cyclic Nacklace(KMP:补齐循环节):要你补充完整一个串,使得该串有循环节构成。解题报告!
POJ 2185Milking Grid(KMP:循环节加强版):转换思维。解题报告!