poj3461 (裸kmp)kmp模板

/*这里是参考的算法导论589页,以及大牛kuangbin的kmp,他的kmp和算法导论代码一致的,博主也看过好多大牛的博客,才选择kuangbin的,因为其他大牛有把模式串代码写的不清楚或直接写错的,kuangbin是完全正确的。*/
 
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
const int N = 100000+10;

char s[N*10], p[N];		/* 母串,模式串*/ 
int nextval[N];		/* next数组只和模式串有关因此长度和模式串相同*/ 
int lens, lenp;		/* 母串len、模式串len*/	 

void getnext()	/* 这里是得到next数组的过程此过程只与模式串长度有关*/ 
{
	int j = 0;	
	int k = -1;
	nextval[0] = -1;	/*next数组默认值next[0] = -1, next[1] = 0,恒定不变,这个可以根据next数组描述画图看看弄清楚*/ 
	while(j < lenp){	/* 这里next数组下标是从0开始的最多next下标到lenp-1,要懂得next数组只和模式串有关和母串无关只求一次即可*/
		if(k == -1 || p[k] == p[j])		/* 这里就是寻找最长真前缀、后缀,的处理过程不懂就根据代码模拟画图很容易懂代码第一次见确实不知道怎么写*/
			nextval[++j] = ++k;
		else
			k = nextval[k];		
	}	
}

int kmp()
{	
	int count = 0;
    int i, j=0;		/*  i,j分别是母串和模式串下标 */
    if(lenp == 1 && lens == 1)
    {
        if(s[0] == p[0]) return 1;
        else return 0;
    }
    getnext();		/* 这里将模式串最长真前缀、真后缀求出*/ 
    for(i = 0; i < lens; i++)	/* 母串查找完*/
    {
        while(j > 0 && s[i] != p[j])
          j = nextval[j];		/* 这里是模式串回溯过程即模式串向后移动*/
        if(p[j] == s[i]) j++;
        if(j == lenp)	/* 已经找到了一个串*/
        {
            count++;
            j = nextval[j];	/* 这里回溯是在母串还没有完全查找完的情况下继续向下查找,所以回溯的,此时因为next数组的个数与模式串长度相同那么此时next[lenp]由于超出模式出长度,即next[lenp] = next[0] = -1,相当于整个串后移一个单位*/
        }
    }
    return count;
}

int main()
{
	int ncase;
	int ans;
	scanf("%d", &ncase);
	while(ncase--){
		scanf("%s%s", p, s);
		lenp = strlen(p);
		lens = strlen(s);	
		printf("%d\n", kmp());
	} 
	return 0;
}

/*和上面一样只是去掉注释而已*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
const int N = 100000+10;

char s[N*10], p[N];		
int nextval[N];		
int lens, lenp;			 

void getnext()	
{
	int j = 0;	
	int k = -1;
	nextval[0] = -1;	
	while(j < lenp){	
		if(k == -1 || p[k] == p[j])		
			nextval[++j] = ++k;
		else
			k = nextval[k];		
	}	
}

int kmp()
{	
	int count = 0;
    int i, j=0;		
    if(lenp == 1 && lens == 1)
    {
        if(s[0] == p[0]) return 1;
        else return 0;
    }
    getnext();	
    for(i = 0; i < lens; i++)	
    {
        while(j > 0 && s[i] != p[j])
          j = nextval[j];		
        if(p[j] == s[i]) j++;
        if(j == lenp)	
        {
            count++;
            j = nextval[j];	
        }
    }
    return count;
}

int main()
{
	int ncase;
	int ans;
	scanf("%d", &ncase);
	while(ncase--){
		scanf("%s%s", p, s);
		lenp = strlen(p);
		lens = strlen(s);	
		printf("%d\n", kmp());
	} 
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值