防止自己忘记KMP算法过程,就自己记录下。我的理解是KMP算法是基于暴力匹配查询上的改进。重点在计算next数组。
主字符串P1('absabbaabccddfssfabsabcc') 待查P2('absabcc')
一.暴力匹配查询(暴力匹配算法)
**暴力匹配查询(暴力匹配算法)**情况如下;
P1[0] 和 P2[0] 匹配 通过 => P1[1] 和P2[1] 匹配 通过 => P1[2]和P2[2] 匹配 通过 => P1[3]和P2[3] 匹配 通过 => P1[4]和P2[4] 匹配 通过 => P1[5]和P2[5] 匹配 不通过 => P1[1] 和 P2[0] 匹配 不通过 => P1[2] 和P2[0] 匹配 不通过 …
即在匹配失败后P1指针回溯到起始位置的下一位,P2指针直接回溯到起始位置,重新开始匹配。
二.next数组
next数组主要是计算P2字符串(或者说匹配失败时已匹配字符串)的最长公共前后缀。
‘a’ 无公共前后缀 0
‘ab’ 前缀’a’ 后缀’b’ 无公共前后缀 0
‘abs’ 前缀’a’,‘ab’ 后缀’s’,‘bs’ 无公共前后缀 0
‘absa’ 前缀’a’,‘ab’,‘abs’ 后缀’a’,‘sa’,‘bsa’ 公共前后缀’a’ 1
‘absab’ 前缀’a’,‘ab’,‘abs’,‘absa’ 后缀’b’,‘ab’,‘sab’,‘bsab’ 公共前后缀’ab’ 2
‘absabc’ 前缀’a’,‘ab’,‘abs’,‘absa’,‘absab’ 后缀’c’,‘bc’,‘abc’,‘sabc’,‘bsabc’ 无公共前后缀 0
‘absabcc’ 前缀’a’ ‘ab’ ‘abs’ ‘absa’ ‘absab’ ‘absabc’ 后缀 ‘c’ ‘cc’ ‘bcc’ ‘abcc’ ‘sabcc’ ‘bsabcc’ 无公共前后缀 0
//这是用JS写的一个简单的next数组
function next( str ){
let i = 0, j = 1,array = [-1];
for(;j<str.length;j++){
if(str[i]===str[j]){
i++;
array[j] = i;
}else{
if( i!=0 && str[0] === str[j] ) i=1;
else i = 0;
array[j] = i;
}
}
return array;
}
三.KMP算法
在了解next数组后,KMP算法的核心已经了解,那么KMP算法是怎样的呢,情况如下:
P1[0] 和 P2[0] 匹配 通过 => P1[1] 和P2[1] 匹配 通过 => P1[2]和P2[2] 匹配 通过 => P1[3]和P2[3] 匹配 通过 => P1[4]和P2[4] 匹配 通过 => P1[5]和P2[5] 匹配 不通过 (已匹配字符串为’absab’)公共前后缀长度为2 => P1[5]和P2[2] 匹配 不通过 (已匹配字符串为’ab’)公共前后缀长度为0 => P1[5]和P2[0] 匹配 不通过 => P1[6]和P2[0] 匹配 通过 => P1[7]和P2[1] 匹配 通过 …
即KMP算法在匹配失败后P1指针不在回溯,而是P2指针根据next数组的公共前后缀的长度继续匹配若P2指针为0时依旧匹配失败,P1指针在继续向下移动。