KMP算法

一、KMP算法的核心思想

KMP算法的核心在于避免重复比较。当在主字符串中匹配模式串时,如果某次匹配失败,朴素算法会将模式串回溯到开头,重新从主字符串的下一个位置开始匹配。而KMP算法通过预处理模式串,计算一个部分匹配表(也叫next数组),记录在匹配失败时模式串应该跳转到的位置,从而跳过不必要的比较。

1.1 问题背景

假设我们有:

  • 主字符串 S="ABABAC"S = "ABABAC"S="ABABAC"
  • 模式串 P="ABA"P = "ABA"P="ABA"

朴素算法会逐一比较:

  • S[0]S[0]S[0] 开始,匹配 PPP,发现 S[2]=′B′≠P[2]=′A′S[2] = 'B' \neq P[2] = 'A'S[2]=B=P[2]=A,匹配失败。
  • 然后从 S[1]S[1]S[1] 开始重新匹配,重复检查已经知道的部分。

KMP算法的优化在于:当匹配失败时,利用模式串 PPP 的信息,决定模式串的指针应该回退到哪里,而不是简单地从头开始。

1.2 部分匹配表(next数组)

部分匹配表是KMP算法的核心数据结构,它记录了模式串中每个位置的前缀和后缀的最长公共长度(即最长相等前后缀)。这个信息帮助我们在匹配失败时快速决定模式串的指针跳转位置。


二、KMP算法的详细步骤

KMP算法分为两个主要部分:

  1. 构建部分匹配表(next数组):对模式串进行预处理,计算每个位置的跳转信息。
  2. 字符串匹配:利用next数组在主字符串中查找模式串。

2.1 构建部分匹配表

部分匹配表的构建是基于模式串自身的模式匹配,目的是找到模式串中每个前缀的最长相等前后缀。

定义

  • 对于模式串 PPP 的位置 iiinext[i]next[i]next[i] 表示以 P[0..i]P[0..i]P[0..i] 为子串时,其最长相等前后缀的长度。
  • 最长相等前后缀是指:子串 P[0..i]P[0..i]P[0..i] 的一个前缀 P[0..k−1]P[0..k-1]P[0..k1] 和后缀 P[i−k+1..i]P[i-k+1..i]P[ik+1..i] 完全相同,且 kkk 尽可能大(但 k≤ik \leq iki)。

举例
模式串 P="ABAB"P = "ABAB"P="ABAB"

  • i=0,P[0]=′A′i = 0, P[0] = 'A'i=0,P[0]=A
    • 前缀和后缀为空,next[0]=0next[0] = 0next[0]=0
  • i=1,P[0..1]="AB"i = 1, P[0..1] = "AB"i=1,P[0..1]="AB"
    • 可能的公共前后缀长度为1(“A” 和 “B”),但 P[0]=′A′≠P[1]=′B′P[0] = 'A' \neq P[1] = 'B'P[0]=A=P[1]=B,无公共前后缀,next[1]=0next[1] = 0next[1]=0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

爱看烟花的码农

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

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

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

打赏作者

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

抵扣说明:

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

余额充值