KMP算法



KMP算法

例如:A=abacabab  B=abab找到BA中第一次出现的起始位置

KMP算法主要是分析了匹配串B的特征,从而在A中搜索时避免用传统暴力法,一一匹配。

如果用传统匹配法,A[3]!=B[3],则应从A[1]开始再次一一比较

 

0

1

2

3

4

5

6

7

 

a

b

a

c

a

b

a

b

1

a

b

a

b

 

 

 

 

2

 

a

 

 

 

 

 

 

3

 

 

a

b

 

 

 

 

4

 

 

 

a

 

 

 

 

5

 

 

 

 

a

b

a

b

如果用KMP算法,则需要先计算Bnext数组,next[i]表示由B[0]B[i]组成的串的部分匹配值(即串的前缀和后缀的最长共有元素的长度。前缀:除了最后一个字符以外,一个字符串的全部头部组合;“后缀”:除了第一个字符以外,一个字符串的全部尾部组合)

 

0

1

2

3

1

a

b

a

b

next

0

0

1

2

经分析可知next[i]是所匹配前缀的下一个字符的下标

每次匹配所需移动的次数即是:匹配的字符数-next[i]

 

 

0

1

2

3

4

5

6

7

 

a

b

a

c

a

b

a

b

1

a

b

a

b

 

 

 

 

2

 

 

a

b

 

 

 

 

那么在第二次匹配的时候就可以向后移动两步,而不用再一一比较,优化运算。尤其是在B串较长,重复串出现较多的情况下能很好的提高运算效率。

那么重点在于如何求next数组呢?

    void makeNext(string P,int len,vector<int> &next)

  {

      int q,k;   //q:模版字符串下标;k:最大前后缀长度

      next[0] = 0;//模版字符串的第一个字符的最大前后缀长度为0

      for (q = 1,k = 0; q < len; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next

      {

          while(k > 0 && P[q] != P[k])//递归的求出P[0]···P[q]的最大的相同的前后缀长度k

              //********************************************************************

  k = next[k-1];          //精髓,重点理解

      //********************************************************************

         if (P[q] == P[k])//如果相等,那么最大相同前后缀长度加1

         {

             k++;

         }

         next[q] = k;

     }

 }

 

程序中k=next[k-1]这一步比较难理解,前面已经说过next[i]是所匹配前缀的下一个字符的下标,而next[k-1]则表示B[0]B[k-1]组成的串的所匹配前缀的下一个字符的下标

0

1

...

q-k

...

q-1

q

...

 

 

 

 

 

0

...

k-1

k

...

q

...

 

 

 

 

 

 

 

 

 

 

假设B[0]B[q-1]组成的串的前缀是B[0]B[k-1],B[0]B[k-1]组成的串的前缀是B[0]B[j-1],那么next[k-1]=j,如果B[j]B[q]相等,那么B[0]B[q]组成的串的前缀是B[0]B[j],否则就需要继续寻找B[0]B[j-1]中的前缀,依次类推。

0

1

....

q-k

...

...

q-1

q

...

 

 

 

 

 

 

 

0

...

...

k-1

k

...

q

...

 

 

 

 

 

 

0

...

j-1

j

 ...

k

...

q

...

同时在真正匹配的时候以A为基准,而尝试在B中找到与A[i]相等的字符,一旦B串找到了末尾,就认为匹配成功。

int findAppearance(string A, int lena, string B, int lenb) {

        // write code here

        vector<int> next(lenb,0);

        makeNext(B,lenb,next);

        int i,q;

        for(i=0,q=0;i<lena;i++)

        {

           while(q>0 && A[i]!=B[q]) q=next[q-1];

           if(A[i]==B[q]) q++;

           if(q==lenb) return i-lenb+1;

        }

        return -1;

    }

 

 

   

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值