• kmp学习笔记


    kmp,扩展 kmp 学习笔记


    说再前边

    字符串水平基本为0,学了第4遍KMP了,总是忘。。。网上资料很多,就不详细讲解了。抄的kuangbin神犇模板

    kmp

    一些知识

    1. 循环节大小:n - nxt[n]

    模板[HDU2087]

    下标从0开始
    nxt[i] 为满足p[i-z...i-1]=p[0...z-1]最大的z值

    #include <cstdio>
    #include <cstring>
    #define rep(i,a,b) for(int i=a;i<=b;++i)
    typedef long long ll;
    const int N = 100000 + 7;
    using namespace std;
    char s[N], p[N];
    int nxt[N], n, m;
    void getnxt() {
        int i, j;
        j = nxt[0] =-1;
        i = 0;
        while(i < m) {
            while(j != -1 && p[i] != p[j]) j = nxt[j];
            nxt[++i] = ++j;
        }
    }
    int kmp_ct() {
        int i, j;
        int ans = 0;
        i = j = 0;
        while(i <= n) {
            while(j != -1 && s[i] != p[j]) j = nxt[j];
            ++i; ++j;
            if(j >= m) {
                ++ans;
                j = 0;//不可重叠
                //j = nxt[j] 可以重叠
            }
        }
        return ans;
    }
    int main() {
        while(~scanf(" %s", s)) {
            if(s[0] == '#') break;
            scanf(" %s", p);
            n = strlen(s), m = strlen(p);
            getnxt();
            printf("%d
    ",kmp_ct());
        }
        return 0;
    }
    
    

    下标从1开始

    #include <cstdio>
    #include <cstring>
    using namespace std;
    const int N=1e6+5;
    int T,nxt[N],n,m;
    char s[N],p[N];
    void getnxt(char p[],int n){
        nxt[1]=0;
        for(int i=2;i<=n;i++){
            int j=nxt[i-1];
            while(j&&s[j+1]!=s[i]) j=nxt[j];
            if(s[j+1]==s[i]) nxt[i]=j+1;
            else nxt[i] = 0;
        }
    }
    int kmp(){
        int ans=0;
        getnxt(p,m);
        int j=0;
        for(int i=1;i<=n;i++){
            while(j&&p[j+1]!=s[i]) j=nxt[j];
            if(p[j+1]==s[i])++j;
            if(j==m) {
                ans++;
                j=0;
            }
        }
        return ans;
    }
    int main(){
        while(scanf(" %s",s+1)!=EOF){
            if(s[1] == '#') break;
            scanf(" %s",p+1);
            n=strlen(s+1),m=strlen(p+1);
            printf("%d
    ",kmp());
        }
        return 0;
    }
    

    扩展kmp

    nxt[i] 表示 x[i...m-1] 与 x[0...m-1] 的最长公共前缀
    ex[i] 表示 y[i...n-1] 与 x[0...m-1] 的最长公共前缀

    #include <bits/stdc++.h>
    const int N = 1e5 + 7;
    using namespace std;
    char x[N], y[N];
    int n, m, nxt[N], ex[N];
    void get_nxt(char x[], int m, int nxt[]) {
        nxt[0] = m;
        int j = 0, k = 1;
        while(j+1 < m && x[j] == x[j+1]) ++j;
        nxt[1] = j;
        for(int i = 2; i < m; ++i) {
            int p = nxt[k] + k - 1, L = nxt[i-k];
            if(i+L < p+1) nxt[i] = L;
            else {
                j = max(0, p-i+1);
                while(i+j < m && x[i+j] == x[j]) ++j;
                nxt[i] = j;
                k = i;
            }
        }
    }
    void exkmp(char x[], int m, char y[], int n, int nxt[], int ex[]) {
        get_nxt(x, m, nxt);
        int j = 0, k = 0;
        while(j < n && j < m && x[j] == y[j]) ++j;
        ex[0] = j;
        for(int i = 1; i < n; ++i) {
            int p = ex[k] + k - 1, L = nxt[i-k];
            if(i+L < p+1) ex[i] = L;
            else {
                j = max(0, p-i+1);
                while(i+j < n && j < m && y[i+j] == x[j]) ++j;
                ex[i] = j;
                k = i;
            }
        }
    }
    int main() {
        scanf(" %s %s", x, y);
        m = strlen(x), n = strlen(y);
        exkmp(x, m, y, n, nxt, ex);
        for(int i = 0; i < m; ++i) printf("%d ", nxt[i]);puts("");
        for(int i = 0; i < n; ++i) printf("%d ", ex[i]);puts("");
        return 0;
    }
    
    
  • 相关阅读:
    python 中 repr() 与str() 区别
    python高级特性 知识 架构总结
    python 递归 之加特技 汉诺塔
    python 递归 反转字符串
    git 的使用
    vim 常用命令
    ubuntu下零基础建站之python基础环境搭建
    Oracle 分组统计,抽取每组前十
    SQL Server2008知识点总结
    java 连接sql server2008配置
  • 原文地址:https://www.cnblogs.com/RRRR-wys/p/9260701.html
Copyright © 2020-2023  润新知