zoukankan      html  css  js  c++  java
  • KMP算法小记

    题前的废话:

    中考结束了呀

    他们都放假了呀

    我在学校学习了呀

    真好呀

    感觉我超废


    首先,我们需要知道KMP算法是干嘛的呀:

    KMP算法是用来处理字符串匹配问题的;

    字符串A=“somebody ak ioi”,字符串B=“ioi”,最暴力的算法O(nm)直接暴力扫描,对于比较小的数据范围还可以,但是要是数据范围一大  (╯°Д°)╯︵┻━┻(直接掀桌)

    所以我们就需要一些字符串算法来解决这个问题,比如KMP

    KMP的工作思路:

    • 用两个指针i和j,分别表示A[i-j+1~i](被匹配串)与B[1~j](匹配串)完全相同,这时如果A[i+1]与B[j+1]不相同,对于KMP算法,是考虑减小j的值(假设j=>k(方便写qwq)),使得A[i-k+1~k]与B[1~k]完全相同(并且使k尽量的大)
    •  举个栗子:(哦对了,KMP算法好像要求字符串从1开始存储可以scanf("%s",a+1)这样存储)

    • A=“abababaababacb” ;B=“ababacb”;
    • 当i=5,j=5时:
    • (找到的新j)

    • 这时前5个时完全匹配的,但是天公不作美,第六个并不匹配,因此我们要考虑更换另一个数j(用k存着好写),因为更换以后A[i-k+1~k]与B[1~k]完全相同,而k<j,因此也就是B串的前k个与A串的从i向前数后k完全相同,因为我们知道B[1~j]与A[i-j+1~i]是完全相同的,因此 i-k+1~i其实是相当于(i-j+1+x~i)取i向前数的k个数与B[1~k]相同,又知道A[i-k+1~i]=A[i-k+1~i]=B[j-k+1,j]也就是说新选的这个j的B串的前j个与后j个完全相同,因此可以判定对于新选择的j只与B串有关,所以可以提前预处理:
      • 对于预处理的方法,我觉得是只可意会不可言传的,但是我还是想写一写,要不然以后连意会都不行啦
      • 举个栗子:

         W :a b a b a c b

        p:0 0 1 2 ??

        假如我们有一个串,并且已经知道了p[1~4]那么如何求p[5]和p[6]呢?

        我们发现,由于p[4]=2,所以w[1~2]=w[3~4],求p[5]的时候,我们发现w[3]=w[5],也就是说我们可以在原来的基础上+1,从而得到更长的相同前后缀,此时p[5]=p[4]+1=3

        W :a b a b a c b

        p:0 0 1 2 3?

        那么p[6]是否也是p[5]+1呢?显然不是,因为w[p[5]+1]!=w[6],那么此时我们可以考虑退一步,看看p[6]是否可以由p[5]的情况所包含的子串得到,即是否p[6]=p[p[5]]+1?

        事实上,这样一直推下去也不行,于是我们知道p[6]=0;

      • 尽管我并没有讲明白,但是可以感性理解一下:
      • 以下是预处理的代码:
        void ych(){
            p[1]=0;
            int f=0;
            for(int i=1;i<len2;++i){
                while(f>0&&s2[f+1]!=s2[i+1]) f=p[f];
                if(s2[f+1]==s2[i+1]) ++f;
                p[i+1]=f;
            }
        }
      • 然后就可以写KMP算法啦:
      • void kmp(){
                int j=0;
            for(int i=0;i<len1;i++){
                while(j>0&&s2[j+1]!=s1[i+1]) j=p[j];
                if(s2[j+1]==s1[i+1]) j++;
                if(j==len2){
                    printf("%d
        ",i+1-len2+1);
                    j=p[j];
                } 
            }
        }

     看一个板子题【洛谷p3375】KMP字符串匹配

    很简单的板子题,完完全全的KMP,就楼上两步代码合起来然后输入输出再搞一搞就好啦;

    CODE:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    char s1[1000010],s2[1000010];
    int p[1000010],len1,len2;
    
    void ych(){
        p[1]=0;
        int f=0;
        for(int i=1;i<len2;++i){
            while(f>0&&s2[f+1]!=s2[i+1]) f=p[f];
            if(s2[f+1]==s2[i+1]) ++f;
            p[i+1]=f;
        }
    }
    
    void kmp(){
            int j=0;
        for(int i=0;i<len1;i++){
            while(j>0&&s2[j+1]!=s1[i+1]) j=p[j];
            if(s2[j+1]==s1[i+1]) j++;
            if(j==len2){
                printf("%d
    ",i+1-len2+1);
                j=p[j];
            } 
        }
    }
    
    int main(){
        scanf("%s",s1+1);
        scanf("%s",s2+1);
        len2=strlen(s2+1);
        len1=strlen(s1+1);
        ych();
        kmp();
        for(int i=1;i<=len2;i++)
          cout<<p[i]<<" ";
        return 0;
    }
  • 相关阅读:
    实操ES6之Promise
    RabbitMQ入门指南
    【从零开始撸一个App】PKCE
    SpringCloud Alibaba Nacos Config 配置中心
    SpringCloud Alibaba Nacos 服务发现 Feign进行消费
    SpringCloud Alibaba Nacos 服务发现 RestTemplate进行消费
    SpringCloud Alibaba Nacos 服务注册
    SpringCloud Alibaba Nacos 服务治理中心
    开发者-管理者 设计陷阱
    java8中的Stream API实战
  • 原文地址:https://www.cnblogs.com/zhuier-xquan/p/11021879.html
Copyright © 2011-2022 走看看