简单易懂KMP算法

KMP算法 ## 浅谈KMP算法

① 寻找next(有的地方是F数组)数组

例如:T 字符串

Index:   0    1    2    3    4    5    6    7    8    9
    T:   A    B    A    B    A    B    A    B    C    A              
    F:   0    0    1    2    3    4    5    6    0    1             (1)
 next:  -1    0    0    1    2    3    4    5    6    0    1        (2)

( 1 ) . 寻找前缀后缀最长公共长度;
( 2 ) . 求next数组;

next数组考虑的是除当前字符外的最长相同牵住后缀,所以通过 ( 1 ) 求得各个前缀后缀的公共元素的最大长度后,只要稍作变形即可:
将第一步中求得的值整体后移一位,然后初值赋为-1;

②求next数组代码

void Getnext()
  {
    int i=0;
    int j=-1;
    int p=strlen(P);
    next[0]=-1;
    while (i<p)
    {
        if (j==-1 || P[i]==P[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else
        {
            j=next[j];
        }
    }
}

例题:已知字符串T,P,求P在T中出现的次数(可以重叠)
input :ZYZ ZYZYZYZ
output:3
代码实现:

 #include<stdio.h> 
 #include<string.h> 
 using namespace std;
 const int N=1e6+5;
 char T[N],P[N];
 int next[N];
 int cnt;void find();
 void Getnext();
 int main()
 {
     scanf("%s %s",T,P);
     find();
     printf("%d\n",cnt);
     return 0;
 }
 void find()
 {
     Getnext();
     int n=strlen(T);
     int m=strlen(P);
     int j=0;
     for(int i=0; i<n; i++)
     {
         while (j && T[i]!=P[j])
         {
             j=next[j];
         }
         if(T[i]==P[j])
         {
             j++;
         }
         if(j==m)
         {
             cnt++;
         }
     }
 }
 void Getnext()
 {
     int i=0;
     int j=-1;
     int p=strlen(P);
     next[0]=-1;
     while (i<p)
     {
         if (j==-1 || P[i]==P[j])
         {
             i++;
             j++;
             next[i]=j;
         }
         else
         {
             j=next[j];
         }
     }
 }

例题链接

若上个例题改为不可重复,则代码实现为:

#include<string.h> 
using namespace std;
const int N=1e6+5;
char T[N],P[N];
int next[N];
int cnt;void find();
void Getnext();
int main()
{
    scanf("%s %s",T,P);                      
    find();                                 
    printf("%d\n",cnt);              
    return 0;
}
void find()
{
    Getnext();
    int n=strlen(T);
    int m=strlen(P);
    int j=0;
    for(int i=0; i<n; i++)
    {
        if(j && T[i]!=P[j])
        {
            j=next[j];
        }
        if(T[i]==P[j])
        {
            j++;
        }
        if(j==m)
        {
            cnt++;
            j=0;
        }
    }
}void Getnext()
{
    int i=0;
    int j=-1;
    int p=strlen(P);
    next[0]=-1;
    while (i<p)
    {
        if (j==-1 || P[i]==P[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else
        {
            j=next[j];
        }
    }
}

相关题目:
1. G -Power Strings
2.D - Prefixes and Suffixes

一些关于next数组的良好性质:
①len-next[len]为此字符串的最小循环节,另外如果len%(len-next[len])==0,此字符串的最小周期就为len/(len-next[len]);

这是本人第一次写博客,如有不对请多包涵,如果对您有所帮助请继续支持。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值