KMP算法理解

KMP讲解

Kmp算法,模式匹配。。。目前效率最高的匹配算法

 

朴素的算法   o(n*m)   

比如    要在  abcabcabcaba 中查找子串 abcaba

朴素的算法

 

第一次匹配 到了箭头的地方失配了

 

 

朴素的算法接下来会从原串的第二个字符比较

于是,从箭头处开始比较,马上就失配了,但是kmp鄙视这种做法,kmp认为这次比较是可以省略的

因为kmp可以这样,在这里开始比较

 

Kmp可以看做是原串不动,而子串尽量往右滑,怎么滑,根据什么滑,next数组

先看next的效果,

如上例在失配后,直接从原串的当前字符c 与子串下标为2的字符比较,

2是什么?正好是子串失配点对应的next数组的数值,

因此,next数组存储的就是当失配后,下一次比较时子串的下标值。

为什么第一个值是-1呢?

第一 好求next ,第二,标记它是子串第一个字符

 

 

接下来看怎么求next数组

当下标从零开始时,对于next[i] 可以看成是

一个最大值,使S(0…x)=S(i-1-x…i-1)    S(a…b)表示S的[a,b]区间的子串

这里的x就是next[i]的值,下标从一开始类似,+1即可,不再赘述。

 

next[i]=x

则S(0…x)=S(i-1-x…i-1)

对于next[i+1]有两种情况 先令k=i 存起来,

第一种,S(x+1)=S(i) 那么next[i+1]=next[i]+1; 很好理解

第二种 S(x+1)!=S(i) 失配了?失配? 失配了怎么办?向右滑?怎么滑?next数组  不过此时的原串和子串都是模式串

   则i=next[i];不停循环 直到S(next[i]+1)=S(i);

那么 next[k]=next[i]+1; k是原来的i ,i是改变之后的值。。。  仔细读读前面几句话,就不会蒙了。。。

那么就可以写程序了。。

 next的求法:

kmp怎么用next呢

   上面求next的方法扩展一下,S为原串,T为子串

   对于T(i),S(j),且next[i]=x,那么满足 T(0…x)=S(j-1-x…j-1) 

同样分两种情况,

第一种,T(i)==S(j)  ++i,++j 即匹配下一个字符,比较S(j+1)和T(i+1)的值

第二种,两者不等,i=next[i];直到满足第一种情况或者i=-1

i=-1时,已经是子串的第一个字符了,应该比较的是S(j+1) T(0) 还是T(i+1)


#include <cstdio>

#include <iostream>

using namespace std;

 

char a[1000];

char b[1000];

int next[1000];

void find_next(char s[],intnext[])

{

      int i=0,j=-1;

    next[i]=-1;

      while(s[i+1])

      {

           if(j==-1||s[i]==s[j]){++i;++j;next[i]=j;}

           else j=next[j];

      }

}

 

int kmp(char s[],char t[],intpos)

{

      int i=pos,j=0;

      while((t[j]||j<0)&&s[i])

      {

        if(j==-1||s[i]==t[j])++i,++j;

           else j=next[j];

      }

      if(!t[j])return i-j;

      return -1;

}

int main()

{

    while(      cin>>a>>b)

      {

      find_next(b,next);

     cout<<endl<<kmp(a,b,0)<<endl;

      }

return 0;

}

 

//test

/*

abcabcabcaba abcaba

000000000001 0001

aaa b

abababa bab

abcdc cdc

*/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值