【模板】kmp以及扩展kmp

kmp算法:
最佳博客: http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html  
这里面kmp算法讲的比较详细,我主要在这写下自己的kmp模板以及需要注意的地方。

void getnext(int t)
{
int i=0,j=-1;
while(i!=t)
   {
    if(j==-1||a[i]==a[j])
    {
     i++;
     j++;
     next[i]=j;
    }
    else j=next[j];
   }
} 

这是kmp算法中求next数组的算法,需要注意的是这个next是指的下一位的比较,而不是本位的比较。
例如:       aabaac中,c的next位是2,也就是说若在c处比较不相等,那么直接回溯到b处再进行比较
                 012345
                 -101012

扩展kmp:
可以在网上看看刘雅琼的ppt。
扩展kmp是求两个数组最大相同前缀数目的节约时间的算法,其时间是线性的,也就是a+b类的,而不是a*b。
扩展kmp模板:

#include<stdio.h>
#include<string.h>
char a[110010],b[110010];
int next[110010],ex[110010];
void getnext(int t)                //这个子函数是求扩展kmp中模板数组的next数组,和kmp算法中的next数组完全不同。
{                                          //扩展kmp算法中next数组是指从这一位开始最大的与全字符串相同的前缀。
 int i,k,L,j,p;
 next[0]=t;
 for(i=0;i<t;i++)
  if(b[i]!=b[i+1]) break;         //在getnext函数中,i是循环节的标记符,p是最大相同前缀的最长长度, 
 next[1]=i;                            // 例如:acabcaca,当循环到第二个a时,p为3,当循环到第三个a时,p为8.
 k=1;p=k+next[k]-1;
 for(i=2;i<t;i++)
 {
  L=next[i-k];
  if(i+L<=p) next[i]=L;
  else
  {
   j=p-i+1;
   if(j<0) j=0;
   while(i+j<t&&b[i+j]==b[j]) j++;    //注意添加限制条件
   next[i]=j;k=i;p=k+next[k]-1;
  }
 }
}
void getex(int t)                            //ex数组是指a串与b串最大相同前缀。
{
 int i,k,p,L,j;
 for(i=0;i<t;i++)
  if(a[i]!=b[i]) break;
 k=0;ex[0]=i;
 for(i=1;i<t;i++)
 {
  p=k+ex[k]-1;
  if(p<0) p=0;
  L=next[i-k];
  if(i+L<=p) next[i]=L;
  else
  {
   j=p-i+1;
   if(j<0) j=0;
   while(i+j<t&&a[i+j]==b[j]) j++;
   ex[i]=j;k=j;
  }
 }
}
int main()
{
 int len,i,j,max;
 while(scanf("%s",a)!=EOF)
 {
  getchar();
  len=strlen(a);
  j=len-1;
  max=0;
  for(i=0;i<len;i++)
  {
   b[j]=a[i];
   j--;
  }
  for(i=0;i<len;i++)
   printf("%c ",b[i]);
  printf("\n");
  getnext(len);
  for(i=0;i<len;i++)
   printf("%d ",next[i]);
  printf("\n");
  getex(len);
  for(i=0;i<len;i++)
   printf("%d ",ex[i]);
  printf("\n");
  /*for(i=0;i<len;i++)
   if(max<ex[i]) max=ex[i];
  printf("%d\n",max);*/
 }
} 



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值