KMP 3种板子

next[i]数组存放 当i不匹配时,下一次比较从next[i]开始。而数组从0开始,0就代表第一个数,1代表第二个数。
读入字符串从0开始

    #include <stdio.h>
    #include <string.h>
    #define maxn 1000010
    char a[maxn],b[maxn],next[maxn];
    void get_next()
    {
        int k=-1;
        int j=0;
        next[0]=-1;
        int b_len=strlen(b);
        while(j<b_len)
        {
            if(k==-1||b[j]==b[k])
            {
                j++;
                k++;
                if(b[j]==b[k])
                	next[j]=next[k];
                else
                	next[j]=k;
            }
            else
            {
                k=next[k];
            }
        }
    }
    int KMP()
    {
        int k=0,j=0;
        int a_len=strlen(a),b_len=strlen(b);
        while(j<a_len)
        {
            if(k==-1||a[j]==b[k])
            {
                j++;
                k++;
            }
            else
            {
                k=next[k];
            }
            if(k==b_len)
            {
                printf("%d\n",j-k+1);
    			k=next[k];
            }
        }
    }
    int main()
    {
        scanf("%s",a);
        scanf("%s",b);
        get_next();
        KMP();
        //printf("%d",next[1]);
        int len=strlen(b);
        for(int i=1;i<=len;i++)
            printf("%d ",next[i]);
    }

读入字符串从1开始,并且next=1代表没有相匹配的,下一次从1开始。
next[i]=1代表第一个数

void get_next()
{
    int j=1;
    int k=0;
    next[1]=0;
    while(j<=n)
    {
        if(k==0||a[j]==a[k])
        {
            j++,k++;
            next[j]=k;
        }
        else
            k=next[k];
    }
}

读入字符串从1开始,并且next【i】存放以i-1为结尾 从头开始 有多少个数相匹配,0代表无,1代表一个。
用于处理循环字符串问题,因为数组准确存放匹配数量。

void get_next()
{
	next[1]=0;
	for(int i=2,j=0;i<=n;i++)
	{
		while(j>0&&a[i]!=a[j+1])j=next[j];
		if(a[i]==a[j+1])j++;
		next[i]=j;
	}
}

例题](http://poj.org/problem?id=1961)

AC代码

#include <stdio.h>
int n,next[1000010];
char a[1000010];
void get_next()
{
	next[1]=0;
	for(int i=2,j=0;i<=n;i++)
	{
		while(j>0&&a[i]!=a[j+1])j=next[j];
		if(a[i]==a[j+1])j++;
		next[i]=j;
	}
}
void solve()
{
    for(int i=2;i<=n;i++)
    {
        if(i%(i-next[i])==0&&i/(i-next[i])>1)                  // i%(i-next[i])==0为了保证循环的完整
            printf("%d %d\n",i,i/(i-next[i]));                 //为什么(i-next[i])就是最小循环长度?
    }                                                          //画图可知当前len个字符等于后len个字符时,
    puts("");                                                  //将字符串平移len个单元,会有a[len+1~2*len]=a[1~len]
}                                                              //而a[2*len+1~3*len]=a[len+1~2*len],如此下去
int main()                                                     //就是最小循环字符串
{                                                             //i-next[next[i]]是次小循环字符串
    int t=1;
    while(scanf("%d",&n)&&n)
    {
        scanf("%s",a+1);
        get_next();
        printf("Test case #%d\n",t++);
        solve();
    }
    
}
发布了88 篇原创文章 · 获赞 8 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_44879687/article/details/98386771
kmp