小翔教你弄懂KMP算法~

KMP算法

简介

KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。该算法相对于 Brute-Force(暴力)算法有比较大的改进,主要是消除了主串指针的回溯,从而使算法效率有了某种程度的提高。(网上抄的)

算法理解与实现

Problem:
KMP算法是用于解决字符串的模式匹配问题,通俗来说就是在字符串s1中寻找s2并将其定位。

Algorithm:
在最初的BF(Brute-Force)算法也就是最容易想到的暴力算法中,最坏的时间复杂度达到O(n*m),在一些时间复杂度有要求的题中是接受不了的,而KMP的时间复杂度达到了O(n+m),也就是说经过处理后可以不用再次从头进行匹配。但是KMP也用一定的局限性即只能处理一对一的匹配问题,多模式匹配详见AC自动机~。

在我个人的理解中,KMP算法的核心是通过匹配该字符前的”操作记录“来得到对于本次操作的有利信息,即该字符失配后应该用前面的哪个字符与该字符再次进行匹配(也可以看作将字串平移),此时该字符前的字符一定是成功与字串匹配的(不理解先跳过这句话),减少不必要的回溯,大大减少了时间复杂度。

next数组就充当了记录“有利信息”的角色。
我自己对于next数组的定义:next[i]是记录s[0]到s[i-1]的前缀和后缀相同的最大位数(如s=“abcdabce”,s[7]=‘e’,next[7]=3,因为s[0]到s[i-1]的前缀s[0]s[1]s[2]="abc"和后缀s[4]s[5]s[6]="abc"是相同的且位数为3),因为s串是从0开始所以s[3]也正好指向最大相同前缀的后一位。

我将next数组的计算和字符串匹配的过程放在了一张图里。
如下:

在这里插入图片描述
在图中会发现,在该字符失配后与next数组所指向的字符进行比对,他们前面的字符总是相同的,无论是在求next数组的过程中和进行模式匹配的过程中都有体现,这就是next数组的魅力,在代码中的体现是在语句"j=next[j]"。

代码:
获取next数组

void Getnext(int next[],String t)
{
   int i=0,j=-1;
   next[0]=-1;
   while(i<t.length-1)
   {
      if(j == -1 || t[i] == t[j])//j等于-1说明该字符和s[0]也匹配失败,则直接到下一个字符的匹配环节
      {
         i++;j++;
         next[i] = j;
      }
      else j = next[j];//点睛之笔!!!
   }
}

拿到next数组的值后就可以进行KMP匹配啦!

int KMP(String s,String t,int next[])
{
   while(i<s.length&&j<t.length)
   {
      if(j==-1 || s[i]==t[j])
      {
         i++;
         j++;
      }
      else j=next[j];    //和求next数组有着异曲同工之妙
   }
   if(j>=t.length)
       return (i-t.length);       
   else
      return (-1);              
}

看懂这里以后还会出现一个遗留的问题,在严老的数据结构中写道:
在这里插入图片描述
为了让这个问题的得到解决只需要在求next数组的语句中加上一句判断:

void Getnext(int next[],String t)
{
   int j=0,k=-1;
   next[0]=-1;
   while(j<t.length-1)
   {
      if(k == -1 || t[j] == t[k])
      {
         j++;k++;
         if(t[j]==t[k])//就是这个!!
            next[j] = next[k];
         else
            next[j] = k;
      }
      else k = next[k];
   }
}

我看过一句话叫做“你能把别人教会你就是真正的会”,前天熬到一点多和KMP斗智斗勇所以我决定把我所理解的写下来,我的室友也都在打呼噜了,明天再让他们学KMP,看我的文章直到学会为止(^ - ^)!这样我也就真正的会了嘿嘿,自从退役以后也没写过博客,正值考研阶段我也决定重拾这份工作了,期待我的下次更新~

撒花~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值