安利一下几个比较通俗易懂的KMP的算法解释:
https://www.cnblogs.com/yjiyjige/p/3263858.html
https://subetter.com/articles/2018/04/kmp-algorithm.html
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
KMP算法的应用
Problem Description
给定两个字符串string1和string2,判断string2是否为string1的子串。
输入包含多组数据,每组测试数据包含两行,第一行代表string1,第二行代表string2,string1和string2中保证不出现空格。(string1和string2大小不超过100字符)
对于每组输入数据,若string2是string1的子串,则输出"YES",否则输出"NO"。
Sample Input
abc a 123456 45 abc ddd
Sample Output
YES YES NO
#include<stdio.h>
#include<string.h>
char s1[110], s2[110];
int nex[110];
void KMP(char s1[], char s2[])
{
int i = 0, j = 0, len1 = strlen(s1), len2 = strlen(s2);
while(i < len1 && j < len2)
{
if(s1[i] == s2[j]) //相等, i 与 j 都向下走
{
i++; j++;
}
else
{
if(j == 0) //s1[i] 与 s2[0] 不相等 只有i向下走
i++;
else //nex
{
j = nex[j-1];
}
}
if(j == len2) //s2 都匹配完了
{
printf("YES\n");
return ;
}
}
printf("NO\n");
}
void get_nex(char s[]) //KMP核心, nex[] 表示 模式串 最长后缀 = 前缀 的长度
{
int len = strlen(s);
nex[0] = 0;
int i;
for(i = 1; i < len; i++)
{
int j = nex[i-1];
while(s[i] != s[j] && j) //如果不相等并且j != 0
j = nex[j-1]; //向前寻找nex[j-1]
if(s[i] == s[j]) //若相等, nex[i-1](最大长度) + 1 == j+1
nex[i] = j+1;
else nex[i] = 0; // j 一直变为0 都没有与s[i]相等的 所以 nex[i] = 0
}
}
int main()
{
while(~scanf("%s", s1))
{
scanf("%s", s2);
get_nex(s2);
KMP(s1, s2);
}
return 0;
}
0123456789 10 11 12 13 14 15 //序号 abcabceabc a b c a b c 0001230123 4 5 6 4 5 6 //nex[i] 表示 在i-1 最大 后缀 = 前缀 的长度 nex[12] = 6, nex[13] 可能 = 7; 一开始定义j = nex[i-1] i = 13时, j=nex[12] = 6; 如果 s[i] == s[j] //若相等, nex[i-1](最大长度) + 1 == j+1 所以 nex[i] = j+1; 但是不相等 s[j] == 'e' (s[6] == 'e') s[i] == 'a' (s[13]) j = nex[j-1] j = 6, j - 1 = 5, s[5] = b 还是不相等 j - 1 = 4, s[4] = a 相等了 停止 所以 nex[13] = 4; 相当于更新最大长度 不相等最大长度缩短 相等 最大长度+1