KMP详解

KMP匹配算法

  • 应用环境:有一个文本串S,和一个模式串P,现在要判断S中是否有和P匹配的子串,并查找P在S中的位置,怎么解决呢?

暴力算法思路

假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有:

如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;如果匹配失败(即S[i]! = P[j]),令i = i - j + 1,j = 0,即每次匹配失败时,i 回溯到上次开始匹配的下一个位置,j 被置为0。

s[N],p[M];
for(int i=1;i<=n;i++){
	bool flag=true;
    for(int j=1;j<m;j++){
        if(s[i]!=p[j]){
            flag=false;
            break;
        }
    }
}

思路

  • next[i]=j:以i为终点后缀和从1开始的前缀相等,且后缀长度最长;
  • 最大前缀数和后缀数要小于字符串本身长度

P=“ababf” 的最长公共前后缀:

  • P[0] 前面没有字符串,所以最长公共前后缀长度为 0。
  • P[1] 前面的字符串为:a,a没有前后缀(前后缀长度要小于字符串长度)。最长公共前后缀长度为 0。
  • P[2] 前面的字符串为:ab,它的前缀为:a,后缀为b。前缀不等于后缀,所以没有公共前后缀,最长公共前后缀长度为 0。
  • P[3] 前面的字符串为:aba,aba 的前缀有:a,ab, 后缀有:a,ba。因为 ab 不等于 ba,所以最长公共前后缀为 a,最长公共前后缀长度为 1。
  • P[4] 前面的字符串为:abab,abab 的前缀有:a,ab,aba,后缀有:a,ab, bab。最长公共前后缀为 ab,长度为 2。

//p是模式串(子串)
p[1,j]=p[i-j+1,i]//长度相等

KMP主要分两步:求next数组、匹配字符串。

求next数组

  • 就是求P数组自身的最长前缀

// s[]是长文本,p[]是模式串,n是s的长度,m是p的长度
for (int i = 2, j = 0; i <= n; i ++ )
    {
    	//j大于0才有意义;当p[i] != p[j + 1]说明不匹配,需要重新
        while (j && p[i] != p[j + 1]) j = ne[j];//将上一个位置的值赋给当前位置
    	
        if (p[i] == p[j + 1]) j ++ ;//当前元素匹配,j++
        ne[i] = j;//记录当前数组下标为i的前缀数
    }

动画

匹配字符串

  • 当匹配过程到上图所示时,
  • s[ a , b ] = p[ 1, j ] && s[ i ] != p[ j + 1 ] 此时要移动p串(不是移动1格,而是直接移动到下次能匹配的位置)
  • 其中1串为[ 1, next[ j ] ],3串为[ j - next[ j ] + 1 , j ]。由匹配可知 1串等于3串,3串等于2串。所以直接移动p串使1到3的位置即可。这个操作可由**j = next[ j ]**直接完成。 如此往复下去,当 j == m时匹配成功。
  • 不满足时相等时,相当于移动最长公共前后缀的长度,保证了此时最长前缀是一样的。
动画

for (int i = 1, j = 0; i <= m; i ++ )
    {
        while (j && s[i] != p[j + 1]) j = ne[j];//相当向后移动字符串
    
        if (s[i] == p[j + 1]) j ++ ;//当最后一个满足是j++就可以与n相等
        if (j == n)
        {
            printf("%d ", i - n);
            j = ne[j];
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值