KMP算法

    KMP算法刚开始学起来有点抽象的,但是理解了之后还是非常清晰的。网上关于KMP算法的讲解非常多也非常详细的,就不过多赘述,下面就仅给出我的模板代码以及做题时踩过的坑和解题思路。

 1 模板代码

void GetNext()
{
    Next[1] = 0;
    int j = 0;
    for(int i=1; i<strlen(b+1); i++)
    {
        while(j>0 && b[j+1]!=b[i+1]) 
            j = Next[j];
        if(b[j+1]==b[i+1])
            j++;
        Next[i+1] = j;
    }
}

int main()
{
    memset(Next, 0, sizeof(Next));
    GetNext();
    int ans = 0, j = 0;
    for(int i=0; i<strlen(a+1); i++)
    {
        while(j>0 && b[j+1]!=a[i+1])
            j = p[j];
        if(b[j+1]==a[i+1])
            j++;
        if(j==strlen(b+1))
        {
            ans++;
            j = 0;        //不可重叠
//          j = Next[j];  //可重叠
        }
    }
}
    

 2 Example

2.1 N 剪花布条

 

#include<bits/stdc++.h>
using namespace std;
 
char a[1010],b[1010];
int p[1010];
 
void pre()
{
    p[1] = 0;
    int j = 0;
    for(int i=1; i<strlen(b+1); i++)
    {
        while(j>0 && b[j+1]!=b[i+1]) 
            j = p[j];
        if(b[j+1]==b[i+1])
            j++;
        p[i+1] = j;
    }
}
 
int main()
{
    while(scanf("%s",a+1)&& a[1] != '#'&&scanf("%s",b+1))
    {
        memset(p,0,sizeof(p));
        pre();
        int ans = 0, j = 0;
        for(int i=0; i<strlen(a+1); i++)
        {
            while(j>0 && b[j+1]!=a[i+1])
                j = p[j];
            if(b[j+1]==a[i+1])
                j++;
            if(j==strlen(b+1))
            {
                ans++;
                j = 0;    //不可重复匹配
            }
        }
        for(int i=1; i<=strlen(b+1); i++)
        	printf("%d ", p[i]);
        printf("\n");
        printf("%d\n", ans);
    }
    return 0;
} 

 2.2 O Simpsons’ Hidden Talents

解题思路:把s1串和s2串合并在一起,通过Next数组记录前缀和后缀公共元素的最大长度。

#include<bits/stdc++.h>
using namespace std;

int Next[100020];
char s[100020], p[100020];
int slen, plen, ulen, ans;

void GetNext()
{
    Next[1] = 0;
    int j = 0;
    for(int i=1; i<=ulen; i++)
    {
        while(j>0 && s[j+1]!=s[i+1]) 
            j = Next[j];
        if(s[j+1]==s[i+1])
            j++;
        Next[i+1] = j;
    }
}

int main()
{
	int cnt;
	while(scanf("%s %s", s+1, p+1) != EOF)
	{
		slen = strlen(s+1);
		plen = strlen(p+1);
		for(int i=slen+1; i<=slen+plen; i++)
			s[i] = p[i-slen];
		ulen = slen + plen;
		GetNext();
		ans = Next[ulen];
		if(ans==0)
			printf("0\n");
		else
		{
			for(int i=1; i<=ans; i++)
				printf("%c", s[i]);
			printf(" %d\n", ans);
		}
	}
}

 问题1: 

abemda

bem

若只是简单的输出Next[strlen(s1+s2)]数组,则以上样例是无法通过的,所以需要在上述代码基础上添加对Next[strlen(s1+s2)]、strlen(s1)、strlen(s2)大小的判断,并通过不断的递归找到不会超过s1、s2长度的前缀和后缀公共元素的最大长度。

while(ans > min(slen, plen))
    ans = Next[ans];

 问题2(这只是一个非常小白的问题):

之前提交的代码没有使用slen, plen, ulen...这些变量,全部使用strlen()直接计算的,导致代码超时。所以还是要记得设变量啊。。

  • 8
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值