KMP算法&&扩展KMP算法(详解)
字符串匹配问题:有一个文本串S,和一个模式串P,现在让你查找P串在S串的位置。
1.朴素算法(暴力匹配)
就是枚举的思想,比如S串现在匹配到第i个位置,P串匹配的第j个位置,这时候就会有匹配成功或者不成功
如果匹配成功,就是P[j]==S[i] ,这时候则继续匹配下一个字符 i++ j++
如果匹配失败 就是P[j]!=S[i] ,这个时候P就需要回到起始位置 ,S串回到 i-j+1这个位置 因为这次匹配P从0位走到了j位,所以S最开始是从i-j这个位置走的,但从i-j这个位置是最终是不能匹配成功的,所以
我们需要从下一个位置开始匹配 ,也就是i-j+1
代码实现:
1 int BF(char *S,char *P){ 2 int lens=strlen(S); 3 int lenp=strlen(P); 4 int i=0,j=0; 5 while(i<lens&&j<lenp){ 6 if(S[i]==P[j]){ 7 i++; 8 j++; 9 }else{ 10 i=i-j+1; 11 j=0; 12 } 13 if(j==lenp-1){ 14 return i+1;//位序+1 15 } 16 } 17 return -1; 18 }
2.KMP算法
KMP算法的经典之处起始就是next[]数组,所有的步骤都是围绕这个数组来进行的,上面的算法之所以叫做暴力匹配,就是因为在不匹配的情况下i j需要从头开始,导致时间复杂度达到O(m*n),m和n分别为两个串的长度,但其实在有些情况下我们是可以不需要重头开始匹配的。
比如模式串P为abaabaca的情况下,假如我们匹配到第7个字符的情况下,j是可以不需要回到0的,因为前6个字符abaaba有一个很明显的特征 前三个和后三个的字符是一样的,假设模式P串匹配的位置是7,文本串S匹配的位置是i,那么i前面的6个字符也一定是abaaba,这时候虽然S和P匹配失败了,但P只需要从回到第4个位置重新进行匹配就可以了,
| P | a | b | a | a | b | a | c | a | |||||||
| S | a | b | a | a | b | a | b | a | a | b | a | c | a |
如上个表格,P走到第七个位置c,S走到底七个位置b,这时候两个字符是不匹配的,但是P是只需要回到第四个字符重新和S的第七个字符匹配就可以

所以我们引入一个定义:最长公共前后缀,next[i]表示的就是前i个字符的最长公共前后缀的长度。
我们需要处理处模式串P的next数组,假设next[i]=k的话,那就是P[0]P[1]..P[K-1]=P[i-k+1]P[i-k+2]...P[i-1]
所以如果P[k]==P[i]的话 next[i+1]=k+1;否则就是next[i+1]=next[k]
浙公网安备 33010602011771号