【模板】KMP
KMP算法
常用于在一个文本串s内查找一个模式串p出现的位置
查找字符串是否为子串
next[] 代表当前字符之前的字符串中,最大长度相同的前缀和后缀
next[j] = 0 或 -1 ,则跳到模式串的开头字符
时间复杂度 O(m+n), 匹配复杂度 O(n), 计算next复杂度 O(n)
KMP算法模板(next[0] = -1)
const int N = 1e6+5; char s1[N],s2[N]; int Next[N]; int len1,len2; void KMP(){ int i = 0,j = 0; while(i < len1 ){ //如果j = -1 ,后者当前字符匹配成功,都为i++,j++ if(j == -1 || s1[i] == s2[j]){ i++; j++; }else{ //如果j != -1 ,且当前字符串匹配失败,则让i不变,j匹配next[j]对应的next值 j = Next[j]; } if(j == len2)//匹配输出当前匹配位置,再返回next[j] cout<<i-len2+1<<endl,j = Next[j]; } }
求解next的模板:
void GetNext(char* p,int next[]){ int plen = strlen(p); next[0] = -1; int k = -1; int j = 0; while(j < plen){ if(k == -1 || p[j] == p[k])
next[++j] = ++k;
else k = next[k];
}
}
注意一下命名,直接命名next会引起冲突,一般命名Next
//str下标从1开始的KMP模板 void get_next(){ for(int i = 2, j = 0; i <= n ; i++){ while(j && str[i] != str[j+1]) j = Next[j]; if(str[i] == str[j+1]) j++; Next[i] = j; } }
基础模板题目:
题目链接:https://www.acwing.com/problem/content/143/
#include <iostream> using namespace std; const int N = 1000010; int Next[N],n; char str[N]; void get_next(){ for(int i = 2, j = 0; i <= n ; i++){ while(j && str[i] != str[j+1]) j = Next[j]; if(str[i] == str[j+1]) j++; Next[i] = j; } } int main(){ int T = 1; while(cin>>n,n){ cin>>str+1; get_next(); cout<<"Test case #"<<T++<<endl; for(int i = 2; i <= n; i++){ int t = i - Next[i]; if(t != i && i % t == 0) cout<<i<<" "<<i/t<<endl; } cout<<endl; } return 0; }
补充:
类似算法还有BM算法、Sunday算法
方便理解的视频:https://www.bilibili.com/video/BV1Px411z7Yo