zoukankan      html  css  js  c++  java
  • KMP学习笔记

    问题

    (字符串匹配问题)给出一个主串A和一个模式串(又叫匹配串)B,询问B在A中出现的次数

    一般做法

    枚举起点,逐位比较A和B
    具体来说,假设枚举的起点为i,当前比较到第j位(指模式串中的第j位),那么我们只需要比较(A[i+j-1])(B[j])就可以了。这个算法的最坏时间复杂度是(O(nm))。(形如 A="aaaaaaaaaaaaab" B="aaaaaaaaab"的询问)

    优化动机

    (O(nm))很多情况下是不能接受的一个时间复杂度,那么我们应该怎么优化呢?有很多博客上会举出一个例子,来证明很多起点是没有必要的。比如说:A="abcccccab" B="abcab" 中,当我们首先枚举起点(i=1),发现当(j=4)时匹配失败,一般做法会枚举起点(i=2),但在这个情况下,明显(A[2]!=B[1]),这个枚举是没有必要的。我们可以从中学到什么呢?

    KMP

    KMP算法的核心在于一个精妙的Next[]数组。(C++的同学要注意,Next最好不要写成next,否则在有一些编译器上会RE。然后就会爆0/(ㄒoㄒ)/~~)Next[]数组的定义如下:

    $ Next[i]=Max { k | B[1..k]=B[i-k+1..i] } $

    假设我们已经处理出Next[]数组,KMP的其余部分可以总结为4个步骤:

    1. 初始化i,j
    2. 跳动j
    3. 比较A[i+1]和B[j+1]
    4. 判断并输出答案

    至于Next数组的处理,那更像是B[]与自身的匹配

    代码

    
    void getNext(){
        Next[1] = 0;
        int j = 0;
        for (int i = 1; i < m; ++i){
            while (j>0 && B[j+1]!=B[i+1]) j = Next[j];
            if (B[j+1] == B[i+1]) ++j;
            P[i+1] = j;
        }
    }
    
    void KMP(){
        int j = 0;
        for (int i = 0; i < n; ++i){
            while (j>0 && B[j+1]!=A[i+1]) j = Next[j];
            if (A[i+1]==B[j+1]) ++j;
            if (j==m){
                printf("%d
    ", i+1-m+1);
                j = Next[j];
            }
        }
    }
    
    来自YJZoier的博客 转载请注明出处
  • 相关阅读:
    十三 .Django(ORM表高级操作)
    十二 .Django ForeighKey自关联(ORM)
    十二 .Django 一对多表ForeighKey(ORM)
    十一 .Django 一对一表OneToOneField (ORM)
    十 .Django 单表操作(ORM)
    八 .Django 模型(models)
    【模板】Lucas定理
    【模板】AC自动机加强版
    【模板】AC自动机
    【POJ3162】Walking Race 树形dp+单调队列+双指针
  • 原文地址:https://www.cnblogs.com/YJZoier/p/KMP.html
Copyright © 2011-2022 走看看