KMP
1.概述
KMP算法就是优化字符串匹配
的问题,就是求一个模板串p在一个串s中出现的问题,比如abcd
在abchgabcgabcdhsd
中是否出现过,出现过几次,每一次出现时的第一个字符的下标等。
这种题我们很容易可以想到使用暴力匹配法,但是在一定的情况下,我们可以优化,比如当一个模板串是abcdabc时,现在已经匹配到了abcdab,但是很不幸运,最后一个c不匹配,暴力的做法是整个字符串继续向右移动重新匹配即从新从第一个字符a进行匹配
,但是我们观察此时的模板串可以发现,abcdab的前缀ab和后缀ab是相等的,所以我们不需要重新拿模板串的第一个字符a与下一个字符进行匹配,只需要指针移动到第一个b的位置,然后将b的下一个字符与其进行匹配即可。
2.kmp的核心
经过上面的图解和概述我们可以知道,kmp的核心就是求一个字符串从头开始的一段串的前缀和后缀相等的长度。
这样我们在进行匹配的过程中,当下一位的字符不匹配时,求一下此时已经匹配的串的前缀和后缀相等的长度,那么匹配时就不需要从头开始匹配了,直接从前缀的最后一个字符的下一个进行匹配即可。
求next数组的过程
// s[]是长串,p[]是模式串,n是s的长度,m是p的长度
//求模式串的Next数组:注意:两个串的下标都是从1开始
//next[1]肯定=0 不用计算了 因为只有一个字符
for (int i = 2, j = 0; i <= m; i ++ )
{
while (j != 0 && p[i] != p[j + 1]) j = next[j];
if (p[i] == p[j + 1]) j ++ ;
ne[i] = j;
}
3.kmp的匹配过程
匹配过程就是上面描述的,当下一位字符不匹配时,不需要从头开始匹配,只需要找一下当前已经匹配的串的前后缀相等的长度,然后直接将指针回退到next[j]的位置,这个位置就是前缀与后缀相等的最后一个位置,例如匹配的是abcab
,此时j在b的位置
,b的下一位不匹配,然后前后缀相等的长度是2,然后j指针回退到第一个b
的位置,在判断j的下一个位置是否与其匹配,如果还不匹配,继续这个过程,最差是从头开始匹配
// s[]是长串,p[]是模式串,n是s的长度,m是p的长度
// 匹配过程 n是长串长度
for (int i = 1, j = 0; i <= n; i ++ )
{
// j+1 是去判断下一位字符是否匹配,不匹配j的索引就是当前已经匹配的索引,去next数组里 找即可
while (j != 0 && s[i] != p[j + 1]) j = next[j];
if (s[i] == p[j + 1]) j ++ ;
//匹配成功一个 继续往后找
if (j == m)
{
j = ne[j];
// 匹配成功后的逻辑
}
}
4.例题
力扣28.实现strStr ——>题解