【算法】模式匹配之KMP

1.算法描述


字符串匹配,是指模式串是否为主串的子串。朴素的匹配算法是一种brute-force:从串的第一个字符开始匹配;当匹配失败时,主串S从第二个字符、模式串P继续从第一个字符开始匹配,…,直至匹配成功或比较到S串的最后一个字符。显然,这种算法的复杂度较为O(m*n),且S串、P串的长度分别为m、n。


鉴于此,Knuth、Pratt和Morris提出了一种高效的匹配算法,复杂度仅为O(m+n)。利用到了模式串的字符信息与匹配失败的位置,以确定下一步比较的主串。先定义:

【算法】模式匹配之KMP_第1张图片

例如,模式串P='abcabcacab'的失配函数



我们定义匹配规则:部分匹配结果是S[i-j]...S[i-1]=P[0]...P[j-1]且S[i]!=P[j];如果j!=0,则S[i]应与P[f(j-1)+1]相比较;如果j=0,则S[i]应与P[0]相比较。


根据上述匹配规则,有如下匹配



失配函数有快速计算方法,可用如下等价公式进行计算




2.Referrence


[1] Horowitz ..., 《数据结构基础》, 清华出版社.

[2] A_B_C_ABC, KMP字符串模式匹配详解.

[3] 模式匹配的一种改进算法----KMP算法.

[4] KMP visulization.


3.问题


3.1 POJ 3461


求模式串在母串中出现的次数


主串数组开小了,Runtime Error。


源代码:

3461 Accepted 1180K 141MS C 941B 2014-03-05 18:59:19

#include "stdio.h"
#include "string.h"

#define MAXW 10000
#define MAXT 1000000

char string[MAXT],pat[MAXW];
int failure[MAXW];

int kmp(char *string, char *pat)
{
	int i=0,j=0,count=0;
	int lens=strlen(string),lenp=strlen(pat);
	while(i<lens)
	{
		if(string[i]==pat[j])
		{
			i++;j++;
		}
		else if(j==0) i++;
		else j=failure[j-1]+1;
		if(j==lenp)              //matched 
			count++;
	}
	return count;
}

void compute_failure(char *pat)
{
	int i,j;
	int lenp=strlen(pat);
	failure[0]=-1;
	for(j=1;j<lenp;j++)
	{
		i=failure[j-1];
		while((pat[j]!=pat[i+1])&&i>=0)
			i=failure[i];
		if(pat[j]==pat[i+1])
			failure[j]=i+1;
		else failure[j]=-1;
	}
}

int main()
{
	int test_cases;
	scanf("%d",&test_cases);
	while(test_cases--)
	{
		scanf("%s%s",&pat,&string);
		compute_failure(pat);
		printf("%d\n",kmp(string,pat));
	}
	return 0;
}


你可能感兴趣的:(【算法】模式匹配之KMP)