zoukankan      html  css  js  c++  java
  • Luogu P3375 【模板】KMP字符串匹配

    第一次写kmp是2月,写错但AC了...第二次是6月,才发现...

    现在是8月,第三次 /cy


    传送门

    KMP (D.E.Knuth - J.H.Morris - V.R.Pratt) 也叫看…,是一种改进的字符串匹配算法,核心是在匹配失败后减少已经匹配过的部分重新匹配。

    原理

    KMP是通过一个f[](fail)——或者叫next的“失配函数”来实现的。

    把已经给出的串称为文本串,要在文本串中找的串称为模式串。

    首先,求出模式串的失配函数。

    fail函数的含义是:在到这一位为止,前缀=后缀的最长长度是多少。

    这里的=是指完全相同,比如ABCABC这样的,而不是对称,并且可以有重叠。

    特别地,前两位(f[0],f[1])为零。

    比如串$ABABAC$,它的fail应该为$001230$ (ABA和ABA重叠了也没事)。

    假设已经求好了fail,那么,假设有文本串$ABABABAC$。

    $ABABABAC$

    $ABABAC$ ←到这里,发现配不上了

    $ABABABAC$

      $ABABAC$ ←退回到第三位,再试试

    实现

    求失配函数

    求失配函数是一个自己和自己匹配的过程。

    void getf() {
        f[0] = f[1] = 0;
        for(int i = 1; i < len2; i++) {
            int j = f[i];
            while(j && p[i]!=p[j]) j = f[j];
            if(p[i] == p[j]) f[i+1] = j+1;
            else f[i+1] = 0;
        }
    }

    已知第i位的失配函数f[i],要求第i+1位的。

    设j=f[i]。f[i]一定在i前面,f[i]已经求好了。

    如果字符串的i+1和j+1位不同(p[i]≠p[j]),那么j不断地跳到自己的失配函数f[j],直到匹配上或j=0为止。

    如果匹配上,f[i+1] = j+1;

    否则如果还是p[i]≠p[j],说明是j=0而不是匹配上了,那么f[j] = 0。

    匹配

    void kmp() {
        int j = 0;
        for(int i = 0; i < len1; i++) {
            while(j && s[i]!=p[j])j = f[j];
            if(s[i] == p[j])j++;
            if(j == len2) {
                printf("%d
    ",1+i-len2+1);
                j = f[j];
            }
        }
    }

    文本串指针i,模式串指针j。

    和刚刚类似,如果没匹配上,就不断把j跳到f[j]。

    如果匹配上了,j往后一位,即j++。

     

    完整代码如下

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #define MogeKo qwq
    using namespace std;
    #include<string>
    const int maxn = 1e6+10;
    int len1,len2,f[maxn];
    string s,p;
    
    void getf() {
        f[0] = f[1] = 0;
        for(int i = 1; i < len2; i++) {
            int j = f[i];
            while(j && p[i]!=p[j]) j = f[j];
            if(p[i] == p[j]) f[i+1] = j+1;
            else f[i+1] = 0;
        }
    }
    
    void kmp() {
        int j = 0;
        for(int i = 0; i < len1; i++) {
            while(j && s[i]!=p[j])j = f[j];
            if(s[i] == p[j])j++;
            if(j == len2) {
                printf("%d
    ",1+i-len2+1);
                j = f[j];
            }
        }
    }
    
    int main() {
        cin>>s>>p;
        len1 = s.length();
        len2 = p.length();
        getf();
        kmp();
        for(int i = 1; i <= len2; i++)
            printf("%d ",f[i]);
        return 0;
    }

     

  • 相关阅读:
    pip安装requests时报 Requirement already satisfied: requests in d:pythonpyth... 的问题解决
    渗透测试靶场
    Spring Security核心类关系图
    Spring security 5 Authorize Configuration
    固定技术栈
    redis 指定端口 启动
    Spring 获取当前activeProfile
    通过进程编号 查询 监听端口
    lombok 插件安装
    idea 快捷键设置
  • 原文地址:https://www.cnblogs.com/mogeko/p/11316385.html
Copyright © 2011-2022 走看看