KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,其核心思想是**避免在主串中回溯指针**

KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,其核心思想是避免在主串中回溯指针,通过预处理模式串生成 next 数组来指导匹配失败时模式串的滑动位置。匹配过程中:

  • 初始化两个指针:i 指向主串 S 的当前字符,j 指向模式串 P 的当前字符(初始均为 0)。
  • S[i] == P[j] 时,双方指针同时后移继续比较。
  • S[i] != P[j] 时,不移动主串指针 i,而是将模式串指针 j 更新为 next[j],即 j = next[j],表示利用已知的最长相等前后缀长度跳过不必要的比较。
  • j == -1(或某些实现中为 0),说明模式串已退回到起始位置,此时将 ij 都加 1,进入下一轮匹配。
  • 一旦 j 达到模式串长度,则匹配成功,返回匹配起始位置。

其中,next[j] 表示模式串中前 j 个字符构成的子串的最长相等真前后缀的长度。该数组可在 O(m) 时间内预处理得到。


数组是数据结构中的基本多维存储结构,其特点如下:

  • 定长性:创建时确定维度和大小,运行期间不可更改。
  • 同构性:所有元素类型相同,存储结构一致。
  • 线性扩展:一维数组是线性表;二维数组可看作“其元素也为线性表”的线性表,例如 A[m][n] 可视为 m 个长度为 n 的行向量组成的线性表。
  • 随机访问:通过下标可在 O(1) 时间内计算地址访问元素(按行/列优先映射到一维内存)。

矩阵常以二维数组表示,而广义表则是更灵活的递归结构,允许元素为原子或子表,是树与图等非线性结构的基础抽象。


KMP 算法提升了朴素匹配的效率(从 O(nm) 到 O(n+m)),而数组作为基础结构支撑了矩阵压缩(如稀疏矩阵的三元组表示)、广义表的存储实现等高级主题。
构造 KMP 算法中的 next 数组,本质是对模式串本身进行“自我匹配”,求出每个位置前缀的最长相等真前后缀(即:最长的、不等于自身的前缀与后缀相等的部分)的长度。next[j] 表示当模式串 P[j] 匹配失败时,新的匹配起点位置。


✅ 构造 next 数组的具体步骤

设模式串为 P,长度为 mnext[0] = -10(取决于实现方式),我们采用常见的一种:

  • next[j] 表示子串 P[0..j-1] 的最长相等真前后缀的长度。
  • 使用双指针法构造:
def compute_next(P):
    m = len(P)
    next = [0] * m        # 初始化 next 数组
    next[0] = -1          # 第一个字符无前缀,设为 -1
    j, k = 0, -1          # j: 当前位置;k: 上一次最长前后缀长度(也作匹配指针)
    
    while j < m - 1:
        if k == -1 or P[j] == P[k]:
            j += 1
            k += 1
            next[j] = k   # 若 P[j]==P[k],则 next[j+1] = k+1
        else:
            k = next[k]   # 不匹配则回退 k
    return next

📘 示例:模式串 P = "ababaa"

我们要为 "ababaa" 构造 next 数组。

j(下标)字符解释说明next[j]
0a首字符,定义为 -1-1
1b子串 “a”:无公共前后缀 → 00
2a子串 “ab”:前缀{a}, 后缀{b} → 无公共 → 00
3b子串 “aba”:前缀 a, ab;后缀 a, ba → 最长公共为 “a” → 长度 11
4a子串 “abab”:前缀 a,ab,aba;后缀 bab,ab,b → 公共 “ab” → 长度 22
5a子串 “ababa”:前缀中 a,aba;后缀中 aba,a → 最长 “aba” → 长度 33

所以最终 next = [-1, 0, 0, 1, 2, 3]

注意:有些教材将 next[0] 设为 0 并整体偏移,但逻辑一致。


🔍 next 数组的作用直观理解

例如在匹配过程中,若 P[5]='a' 失败,j = next[5] = 3,意味着我们可以跳到 P[3] 继续比较,因为前面已有长度为 3 的公共前后缀 "aba",无需重新从头开始。


💡 小结

  • next 数组基于模式串自身结构构建。
  • 核心思想:利用已知的“最长相等前后缀”避免无效匹配。
  • 时间复杂度:O(m),空间复杂度:O(1) 辅助变量。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bol5261

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值