[填坑][主线任务]MP&KMP算法

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[填坑][主线任务]MP&KMP算法相关的知识,希望对你有一定的参考价值。

当时一直就没有理解QAQ,觉得会hash就够了,但是想到fail数组有很多神奇的妙用,于是来填这个坑

技术分享


先讲MP算法:

我就直接说fail数组的含义吧(从0开始字符串下标):

fail[i]表示0~i-1这个串的最长border的长度,同时也是重新开始匹配的将要匹配的那个位置下标。

举个小栗子:对于字符串 abcdabd 

fail[6]=2,即abcdab的最长border的长度为2(ab),匹配失败的时候,下标跳到fail[6](为2)再来匹配,即从‘c’字母开始匹配(因为前边的‘ab’已经匹配成功了)

比如这个匹配:

技术分享

当匹配‘d’与空格失败后,fail[6]=2,跳到2再来拿‘c’去和空格匹配,而‘c’前边的‘ab’已经匹配成功了

所以我们的匹配代码是这样的:

void work() {
    int j=0;
    pos(i,0,len2-1) {
        while(j&&P[j]!=Q[i]) j=fail[j];
		//一直匹配不上一直往前跳,直到到了最开始或者匹配成功 
        if(P[j]==Q[i]) j++;//匹配成功继续向后匹配 
        if(j==len) {
            ans++;
            j=fail[j];
			//如果全串匹配成功了,直接跳到全串的fail,重新开始匹配 
        }
    }
}  

那么我们怎么求fail数组呢?其实就是自己和自己匹配

我们已经知道fail[i-1],即我们知道0~i-2的最长border,那我们求fail[i],就要拿p[i-1]和fail[i-1]去比较,如果相等就是fail[i]=fail[i-1]+1,如果不相等就相当于失配了,就再往前跳fail,直到跳到最开始或者找到可以匹配的位置

代码实现:

void getfail(){
	len=strlen(p);
	fail[0]=fail[1]=0;
	int k=0;
	pos(i,2,len){
		while(k&&p[k]!=p[i-1]) k=fail[k];
		if(p[k]==p[i-1]) k++;
		fail[i]=k;
	}
}

KMP算法:

MP算法中的fail是最长border,KMP算法有一丝丝的不同,就是fail数组存的是最优border  

代码实现就加了1行:

void getfail() {
    fail[0]=fail[1]=0;
    int k=0;
    pos(i,2,len) {
        while(k&&P[k]!=P[i-1]) k=fail[k];
        if(P[k]==P[i-1]) k++;
        if(P[k]!=P[i]) fail[i]=k;
        else fail[i]=fail[k];
    }
} 

就是说我们fail匹配到之后,我们需要再比较一下fail与当前位置,相当于借鉴一下前人的经验

意思就是说,如果我们接下来匹配的内容前边已经匹配过,显然注定会失败,所以我们的fail再向前跳一个,以达到最优的目的QvQ


接下来又是愉快的刷题:

 

以上是关于[填坑][主线任务]MP&KMP算法的主要内容,如果未能解决你的问题,请参考以下文章

数据结构&算法-KMP匹配算法

数据结构&算法-KMP匹配算法

[算法讲解] KMP & EXKMP

字符串与模式匹配算法:KMP算法

Java 数据结构 & 算法宁可累死自己, 也要卷死别人 17 KMP 算法

Java 数据结构 & 算法宁可累死自己, 也要卷死别人 17 KMP 算法