Oulipo poj-3461

    题目大意:给你两个字符串s和p,问s中有多少个等于p的子串。

    注释:$1\le strlen(p)\le 10^4\qquad1\le strlen(s)\le 10^6$

      想法:刚刚学习KMP,先来一道裸题。什么是KMP?

      KMP是一种字符串匹配算法。如果求出在一个母串中子串出现的位置,我们用一种办法就是枚举母串中任意一个位置pos[i]作为子串开始节点,然后向后匹配,如果匹配成功或者失配,我们都必须重新从pos[i]+1开始重新枚举。我们假设已经匹配到了p串的j号字符,但是我们发现p串中的一些字符是不需要进行重新匹配的,我们就可以通过next数组来使得当前的j跳到next[j]来重新进行匹配,这样的算法,就是KMP(3个人名)。

        附上版子

      这是求next数组的版子

void GetNext()
{
	int pLen=strlen(p);
	int k=-1;
	int j=0;
	next[0]=-1;
	while(j<pLen)
	{
		if(k==-1||p[j]==p[k])
		{
			++k;
			++j;
			next[j]=k;
		}
		else k=next[k];
	}
}

     然后我们一起看一下实现KMP的版子。

void KmpSearch()
{
	int i=0;
	int j=0;
	int sLen=strlen(s);
	int pLen=strlen(p);
	while(i<sLen)
	{
		if(j==-1 || s[i] == p[j] ) i++ , j++;
		else j=next[j];
		if(j==pLen)
		{
			ans++,j=next[j];
		}
	}
}

    最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char p[10010];
char s[1001000];
int next[10010];
void GetNext()
{
	int pLen=strlen(p);
	int k=-1;
	int j=0;
	next[0]=-1;
	while(j<pLen)
	{
		if(k==-1||p[j]==p[k])
		{
			++k;
			++j;
			next[j]=k;
		}
		else k=next[k];
	}
}
int ans=0;
void KmpSearch()
{
	int i=0;
	int j=0;
	int sLen=strlen(s);
	int pLen=strlen(p);
	while(i<sLen)
	{
		if(j==-1 || s[i] == p[j] ) i++ , j++;
		else j=next[j];
		if(j==pLen)
		{
			ans++,j=next[j];
		}
	}
}
void original()
{
	memset(next,0,sizeof next);
	ans=0;
}
int main()
{
	int cases;
	scanf("%d",&cases);
	while(cases--)
	{
		original();
		scanf("%s%s",p,s);
		GetNext();
		KmpSearch();
		printf("%d\n",ans);
	}
	return 0;
}

     小结:第一道KMP(好像大部分KMP的题都被我用hashShi过了)