[填坑][主线任务]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算法的主要内容,如果未能解决你的问题,请参考以下文章