从零实现KMP:手写next数组生成逻辑

KMP算法中的next数组实现

KMP算法的核心在于预处理模式串生成next数组,用于匹配失败时快速跳转。next[i]表示模式串P[0..i-1]的最长公共前后缀长度(不包括整个子串本身)。

数学定义

设模式串为$P$,长度为$m$:

  • $next[0] = -1$(空串无前后缀)
  • 对于$i > 0$,$next[i] = \max{k \mid 0 \leq k < i,\ P[0..k-1] = P[i-k..i-1]}$
生成逻辑(手写代码)
def build_next(pattern: str) -> list:
    m = len(pattern)
    next_arr = [-1] * m  # 初始化数组
    i, j = 0, -1        # i: 当前下标, j: 前缀指针
    
    while i < m - 1:     # 注意只需遍历到 m-2
        # 字符匹配成功时扩展前缀
        if j == -1 or pattern[i] == pattern[j]:
            i += 1
            j += 1
            next_arr[i] = j  # 记录最长公共前后缀长度
        # 失配时回退前缀指针
        else:
            j = next_arr[j]
    return next_arr

关键步骤解析
  1. 初始化

    • next_arr[0] = -1(固定值)
    • 双指针i=0(主指针), j=-1(前缀指针)
  2. 循环处理($i$从$0$到$m-2$):

    • 匹配成功($P[i] = P[j]$):
      • 同时移动$i$和$j$
      • 设置$next[i] = j$(当前最长公共长度)
    • 匹配失败($P[i] \neq P[j]$):
      • 利用已计算的$next$值回退:$j = next[j]$
      • 当$j=-1$时强制移动$i$
  3. 终止条件

    • $i$达到$m-1$时停止($next$最后一个值由倒数第二位置推导)
示例演示

以模式串"ababc"为例:

步骤   i   j   P[i]  P[j]  操作         next数组
初始化 0  -1   'a'   N/A   → i=1,j=0   [-1, 0, -1, -1, -1]
1     1   0   'b'   'a'   失配 j=next[0]=-1
2     1  -1   'b'   N/A   → i=2,j=0   [-1, -1, 0, -1, -1]
3     2   0   'a'   'a'   匹配 → i=3,j=1   [-1, -1, 0, 1, -1]
4     3   1   'b'   'b'   匹配 → i=4,j=2   [-1, -1, 0, 1, 2]
5     4   2   'c'   'a'   失配 j=next[2]=0
6     4   0   'c'   'a'   失配 j=next[0]=-1
7     4  -1   'c'   N/A   终止
最终next = [-1, -1, 0, 1, 2]

特性说明
  • 时间复杂度:$O(m)$(每个字符最多比较两次)
  • 空间复杂度:$O(m)$
  • 跳转原理:当$P[i]$匹配失败时,直接跳转到$P[next[i]]$继续匹配,避免回溯主串

此实现符合KMP原始论文规范,实际使用时需注意不同文献中$next$数组起始下标可能不同(有0-based和1-based两种常见形式)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值