KMP算法

本文深入探讨了KMP算法的核心思想,包括如何在字符串匹配过程中通过next数组实现高效的比较。首先解释了匹配字符串的过程,强调了在不匹配时如何利用已有的相同前缀来移动模式串,减少了比较次数。接着详细阐述了next数组的构建原理,通过分析字符串的前缀和后缀找出最长公共部分,以提高匹配效率。提供的代码示例展示了KMP算法的实现细节。相较于暴力匹配,KMP算法显著提升了搜索性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

KMP算法的思想是:在模式串和主串匹配过程中,当遇到不匹配的字符时,对于主串和模式串中已对比过相同的前缀字符串,找到长度最长的相等前缀串,从而将模式串一次性滑动多位,并省略一些比较过程。(遇到两个字符不匹配的情况时,希望可以多跳几个字符,减少比较次数);

​ KMP主要分两步:求next数组、匹配字符串。个人觉得匹配操作容易懂一些,疑惑我一整天的是求next数组的思想。所以先把匹配字符串讲一下。

一.匹配字符串

 s串 和 p串都是从1开始的。i 从1开始,j 从0开始,每次s[ i ] 和p[ j + 1 ]比较

当匹配过程到上图所示时,

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时匹配成功。

代码:(前提输入n,输入字符串p(长度为n),输入m,输入字符串s(长度为m)//字符串p短于s

n<m;

for(int i = 1, j = 0; i <= m; i++)
{
    while(j && s[i] != p[j+1]) j = ne[j];
    //如果j有对应p串的元素, 且s[i] != p[j+1], 则失配, 移动p串
    //用while是由于移动后可能仍然失配,所以要继续移动直到匹配或整个p串移到后面(j = 0)

    if(s[i] == p[j+1]) j++;
    //当前元素匹配,j移向p串下一位
    if(j == n)
    {
        //匹配成功,进行相关操作
        j = ne[j]; //继续匹配下一个子串
        cout<<i-n; 
    }
}

求next数组的思想:

next数组的理解:对next[ j ] ,是p[ 1, j ]串中前缀和后缀相同的最大长度(部分匹配值)

即从p字符串第一个字母到第j个字母前缀(从第一个字母开始)和后缀(从最后一个字母开始)相同的长度;

如;

对 p = “abcab”

pabcab
下标12345
next[ ]00012


对next[ 1 ] :前缀 = 空集—————后缀 = 空集—————next[ 1 ] = 0;

对next[ 2 ] :前缀 = { a }—————后缀 = { b }—————next[ 2 ] = 0;

对next[ 3 ] :前缀 = { a , ab }—————后缀 = { c , bc}—————next[ 3 ] = 0;

对next[ 4 ] :前缀 = { a , ab , abc }—————后缀 = { a . ca , bca }—————next[ 4 ] = 1;

对next[ 5 ] :前缀 = { a , ab , abc , abca }———后缀 = { b , ab , cab , bcab}————next[ 5 ] =2

代码

for(int i=2,j=0;i<=n;i++){
		while(j&&p[i]!=p[j+1])j=ne[j];
		if(p[i]==p[j+1])j++;
		ne[i]=j;
	}

这里插入一个流程图

 关于KMP算法就这些,相比于暴力,KMP会大大节省时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值