zoukankan      html  css  js  c++  java
  • 字符串(2)KMP算法

    给你两个字符串a(len[a]=n),b(len[b]=m),问b是否是a的子串,并且统计b在a中的出现次数,如果我们枚举a从什么位置与匹配,并且验证是否匹配,那么时间复杂度O(nm),

    而n和m的范围为10^5,这样做显然超时,因此我们就要用到神奇的KMP算法,在O(n)的时间内解决这一类的问题。

    首先给出两个字符串

    A:abababaababacb

    B:ababacb

    首先我们思考朴素算法,我们枚举A串的每一位作为开始与B串匹配的位置,然后一位一位进行检验,如果匹配失败则会从B串的开始重新匹配,这也是朴素算法为什么会超时的原因所在,那么我们可不可以不从B串的开始与A串的下一位匹配,而是直接找到一个可以与A串枚举到的那一位匹配的B串的一个位置,这样我们只需要扫描一遍字符串A,然后在更新可以匹配到B串的哪一个位置。

    举个例子:

    对于字符串A,B,他们的前五位是一样的,可以匹配。

    但是第6位就无法匹配了,所以我们需要调整B串的位置重新匹配,通过观察我们发现B串的前3位和A串的3到5位可以匹配,所以我们可以直接将j的值改为3,然后继续和A串匹配。

    这样一来我们就又可以继续向后匹配了。

    但是i=8时又无法匹配了,我们需要继续调整B串的位置以便于进行匹配。

     

    然而这样仍然不能匹配,那就继续移动,直至可以匹配为止。

    最终我们成功将A串与B串匹配成功。

     我们根据B串的移动规律可以构造出这样的一个p数组,使得p[j]表示B[1…j]=B[j-k+1…j]的k的最大值(即B串前j个字符最长相同的前缀和后缀的长度),这样我们就可以直接将B串进行上述的移动操作了。

     1 void kmp()
     2 {
     3     int j=0;
     4     for(int i=0;i<n;i++)
     5     {
     6         while(j>0&&b[j+1]!=a[i+1]) j=p[j];//如果下一位不能匹配就移动B串 
     7         if(b[j+1]==a[i+1]) j++;//如果可以匹配就继续匹配下一位 
     8         if(j==m)//这里表示完全匹配,也就是A串和B串成功匹配了 
     9         {
    10             printf("%d
    ",i-m+2); 
    11             j=p[j];//这样的目的是为了不遗漏重叠的匹配 
    12         }
    13     }
    14 }
    kmp匹配

    接下来我们思考如何求这个p数组,假如我们知道了p[1…j-1]的值,那我们如何求p[j]的值呢?如果B[i+1]==B[j+1],那么显然p[j]=p[j-1]+1,因为这相当于前缀后缀都加了一个相同的字符,总长都加上1,那么若果B[i+1]!=B[j+1]我们可以考虑将j向后退一步,也就是减小j的值,再进行匹配。

     1 void pre()
     2 {
     3     p[1]=0;
     4     int j=0;
     5     for(int i=1;i<m;i++)
     6     {
     7         while(j>0&&b[i+1]!=b[j+1]) j=p[j];
     8         if(b[i+1]==b[j+1]) j++;
     9         p[i+1]=j;
    10     }
    11 }
    求p数组

    这样我们就成功完成了kmp算法

  • 相关阅读:
    dblink && 视图 数据库二合一
    oracle mybatis 逆向工程 应当注意的问题
    关于使用vue搭建前后端分离的项目,部署过程遇到的问题
    详解vue静态资源打包中的坑与解决方案
    bootstarap table 分页导出 vue版
    react中两个控件不是父子关系该怎么传递消息或任意控件怎么传递消息
    虚拟DOM中key的作用
    修改Antd的List列表的单个数据行
    移动端开发如何关闭手机键盘
    在一行显示两个数据,左边的数据右对齐,右边的数据左对齐
  • 原文地址:https://www.cnblogs.com/snowy2002/p/10414285.html
Copyright © 2011-2022 走看看