#include <iostream>
#include <algorithm>
#include <memory>
#include <cstring>
using namespace std;
const int maxn = 1000;
int mynext[maxn], nextval[maxn];
//t = next[j]表明p[0,j]的前缀和后缀相等的末尾下标是t,即p[0,t]是完全匹配的
//next[j]表示j+1位匹配失败但j往前的匹配成功应该退回去的位置,退回去后仍然保持p[0,next[j]]是前后缀匹配的
void getNext(char s[], int len){
int j = -1;//p[0,j]是已经完全匹配的
mynext[0] = -1;//这个是没有匹配的
for(int i = 1; i < len; i ++){
//如果当前比较位i不等于已经完全匹配的下一个字符 ,j继续向前移动直到等于或j == -1
while(j != -1 && s[i] != s[j + 1]){
j = mynext[j];//反复令j回退,每一步回退都会保证p[0,j]是完全匹配的。因为[0,j]是匹配的,也就是原串是这样的,要想缩短后继续匹配,其实是找[0,j]的最长相等前后缀。即next[j];
}
//上面的迭代有两种可能,
//一种是j=-1,代表没有匹配的,那这步比较是为了判断首字母相不相同
//还有就是找到一个位置 使得s[i] == s[j + 1],那么理应向后移动一个
if(s[i] == s[j + 1]){
j ++;
}
mynext[i] = j;
}
}
void getNextval(char s[], int len){
int j = -1;//表示模式串中已经匹配的下标
nextval[0] = -1;
//第i位是不匹配的
for(int i = 1; i < len; i ++){
while(j != -1 && s[i] != s[j + 1]){
j = nextval[j];
}
if(s[i] == s[j + 1]){
j ++;
}
//如果一个也没有匹配或者超过一个匹配上了,
//这时不匹配的位置i已经匹配上了,为了避免重复,需要判断下一位相同不相同
if(j == -1 || s[i + 1] != s[j + 1]){
nextval[i] = j;
}
else nextval = nextval[j];
}
}
bool KMP(char text[], char patten[]){
int n = strlen(text), m = strlen(patten);
getNext(patten, m);//得到next数组
int j = -1;//表示p[0,j]已经与text匹配
for(int i = 0; i < n; i ++){
while(j != -1 && text[i] != patten[j + 1]){
j = mynext[j];
}
//还是判断当前位有没有匹配上
if(text[i] == text[j + 1]){
j ++;
}
//判断完全已经匹配的是不是p[0, m-1]
if(j == m - 1){
return true;
}
}
return false;
}
int main()
{
char a[10], b[10];
scanf("%s%s", a, b);
bool res = KMP(a, b);
if(res) printf("Yes\n");
else printf("No\n");
return 0;
}
KMP算法
最新推荐文章于 2024-10-20 09:00:00 发布