【模板】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

 

posted @ 2020-10-05 15:36  我不秃  阅读(111)  评论(0编辑  收藏  举报