当前位置: 首页 > news >正文

考研数据结构之串的模式匹配算法——KMP算法详解(包含真题及解析)

考研数据结构之串的模式匹配算法——KMP算法详解


一、KMP算法背景与核心思想

KMP算法(Knuth-Morris-Pratt算法)是字符串匹配领域的经典算法,由三位科学家共同提出。相较于传统的暴力匹配算法(BF算法),KMP通过预处理模式串生成部分匹配表(next数组),在匹配失败时跳过已知不可能匹配的位置,从而将时间复杂度优化至O(n+m)(主串长度n,模式串长度m)。


二、KMP算法核心概念

1. 前缀与后缀

  • 前缀:除最后一个字符外,字符串的所有头部子串。例如,“ABCD"的前缀包括"A”, “AB”, “ABC”。
  • 后缀:除第一个字符外,字符串的所有尾部子串。例如,“ABCD"的后缀包括"BCD”, “CD”, “D”。

2. 最长公共前后缀长度(next数组)

  • 定义:对于模式串的每个子串(从首字符到当前位置),其最长相等前缀和后缀的长度。
  • 作用:当字符匹配失败时,决定模式串的回退位置,避免主串指针回溯。

三、next数组构建步骤(手推过程)

以模式串"ABABAC"为例,演示next数组构建:

索引i字符最长公共前后缀长度(next[i])推导过程
0A0单字符无前后缀
1B0"AB"无公共前后缀
2A1“ABA"的最长公共前后缀为"A”
3B2“ABAB"的最长公共前后缀为"AB”
4A3“ABABA"的最长公共前后缀为"ABA”
5C0"ABABAC"无公共前后缀

关键公式
next[i] = max{k | 模式串[0..k-1] == 模式串[i-k..i-1], 0≤k<i}


四、KMP算法匹配流程(实例解析)

问题:主串"ABABABACAB",模式串"ABABAC",求匹配位置。

  1. 初始化:主串指针i=0,模式串指针j=0
  2. 匹配成功ij同步后移,直到j=5时,主串[i]=A vs 模式串[j]=C不匹配。
  3. 查找next数组next[5]=0,模式串回退至j=0,主串i保持当前位。
  4. 继续匹配:最终在主串索引4处完成匹配。

核心代码逻辑

def KMP(main_str, pattern):
    next = get_next(pattern)
    i = j = 0
    while i < len(main_str) and j < len(pattern):
        if j == -1 or main_str[i] == pattern[j]:
            i += 1
            j += 1
        else:
            j = next[j]  # 核心:模式串回退
    return j == len(pattern)

五、KMP算法优缺点分析

优点

  • 时间效率高:主串指针无需回溯,适合处理流式数据。
  • 稳定性强:最坏时间复杂度为O(n+m),优于BF算法的O(n*m)。

缺点

  • 空间开销:需额外存储next数组(O(m)空间)。
  • 预处理成本:对短模式串或少量匹配场景,性价比低于BF算法。

六、KMP算法应用场景

  1. 文本编辑器:实现快速查找/替换功能。
  2. 搜索引擎:处理海量文本的关键字匹配。
  3. 生物信息学:DNA序列比对(如寻找基因片段)。

七、考研真题解析

KMP算法是考研数据结构的重点内容之一,尤其在408统考中频繁出现。以下通过几道经典真题,深入解析KMP算法的解题思路和技巧。


真题1:2023年408真题

题目描述

已知主串S="ababcababak",模式串T="ababac",求:

  1. 模式串T的next数组。
  2. 主串S与模式串T的匹配过程,并指出首次匹配成功的位置。
解析
第一步:构建next数组

根据KMP算法的核心思想,next数组表示模式串每个位置对应的最长公共前后缀长度。以下是构建next数组的过程:

索引i字符最长公共前后缀长度(next[i])推导过程
0a0单字符无前后缀
1b0"ab"无公共前后缀
2a1“aba"的最长公共前后缀为"a”
3b2“abab"的最长公共前后缀为"ab”
4a3“ababa"的最长公共前后缀为"aba”
5c0"ababac"无公共前后缀

最终得到模式串T="ababac"的next数组为:
[0, 0, 1, 2, 3, 0]

第二步:匹配过程

初始化主串指针i=0,模式串指针j=0,按照KMP算法逐步匹配:

  1. S[0]="a" vs T[0]="a",匹配成功,i=1, j=1
  2. S[1]="b" vs T[1]="b",匹配成功,i=2, j=2
  3. S[2]="a" vs T[2]="a",匹配成功,i=3, j=3
  4. S[3]="b" vs T[3]="b",匹配成功,i=4, j=4
  5. S[4]="a" vs T[4]="a",匹配成功,i=5, j=5
  6. S[5]="c" vs T[5]="c",匹配失败,查next数组得next[5]=0,回退j=0,主串i=5保持不变。
  7. S[5]="c" vs T[0]="a",匹配失败,继续查next数组得next[0]=-1,主串i=6,模式串j=0
  8. S[6]="a" vs T[0]="a",匹配成功,i=7, j=1
  9. 依次类推,最终在主串索引5处完成匹配。

答案:首次匹配成功的位置为索引5


真题2:2022年408真题

题目描述

已知主串S="abacababcabacabaad",模式串T="abacab",求:

  1. 模式串T的next数组。
  2. 主串S与模式串T的匹配过程,并指出所有匹配成功的位置。
解析
第一步:构建next数组

对模式串T="abacab"逐位计算最长公共前后缀长度:

索引i字符最长公共前后缀长度(next[i])推导过程
0a0单字符无前后缀
1b0"ab"无公共前后缀
2a1“aba"的最长公共前后缀为"a”
3c0"abac"无公共前后缀
4a1“abaca"的最长公共前后缀为"a”
5b2“abacab"的最长公共前后缀为"ab”

最终得到模式串T="abacab"的next数组为:
[0, 0, 1, 0, 1, 2]

第二步:匹配过程

初始化主串指针i=0,模式串指针j=0,逐步匹配:

  1. S[0]="a" vs T[0]="a",匹配成功,i=1, j=1
  2. S[1]="b" vs T[1]="b",匹配成功,i=2, j=2
  3. S[2]="a" vs T[2]="a",匹配成功,i=3, j=3
  4. S[3]="c" vs T[3]="c",匹配成功,i=4, j=4
  5. S[4]="a" vs T[4]="a",匹配成功,i=5, j=5
  6. S[5]="b" vs T[5]="b",匹配成功,找到第一个匹配位置0
  7. 继续匹配剩余部分,最终发现另一个匹配位置为6

答案:匹配成功的位置为索引06


真题3:2021年408真题

题目描述

给定主串S="ababababca",模式串T="ababc",求:

  1. 模式串T的next数组。
  2. 主串S与模式串T的匹配过程,并说明匹配失败的原因。
解析
第一步:构建next数组

对模式串T="ababc"逐位计算最长公共前后缀长度:

索引i字符最长公共前后缀长度(next[i])推导过程
0a0单字符无前后缀
1b0"ab"无公共前后缀
2a1“aba"的最长公共前后缀为"a”
3b2“abab"的最长公共前后缀为"ab”
4c0"ababc"无公共前后缀

最终得到模式串T="ababc"的next数组为:
[0, 0, 1, 2, 0]

第二步:匹配过程

初始化主串指针i=0,模式串指针j=0,逐步匹配:

  1. S[0]="a" vs T[0]="a",匹配成功,i=1, j=1
  2. S[1]="b" vs T[1]="b",匹配成功,i=2, j=2
  3. S[2]="a" vs T[2]="a",匹配成功,i=3, j=3
  4. S[3]="b" vs T[3]="b",匹配成功,i=4, j=4
  5. S[4]="a" vs T[4]="c",匹配失败,查next数组得next[4]=0,回退j=0,主串i=4保持不变。
  6. 后续匹配过程中,发现无法找到完全匹配的位置。

答案:匹配失败,原因在于主串S中不存在完整的模式串T


八、总结

通过以上真题解析可以看出,KMP算法的解题步骤主要包括以下两部分:

  1. 构建next数组:利用最长公共前后缀的思想,逐位计算模式串的next值。
  2. 匹配过程:结合next数组优化匹配效率,避免重复扫描主串。

建议考生在备考时,重点掌握手推next数组的方法和匹配逻辑,并结合代码实现加深理解。

相关文章:

  • 回顾CSA,CSA复习
  • Linux的网络配置的资料
  • python对mysql数据库的操作
  • 深度学习中多机训练概念下的DP与DDP
  • C++ 编程指南35 - 为保持ABI稳定,应避免模板接口
  • SQL查询语句的执行顺序
  • C++(初阶)(十一)——list
  • 数据结构实验6.1:矩阵的螺旋方阵输出
  • 在ArcGIS Pro中将栅格NoData值修改为特定值
  • QEMU源码全解析 —— 块设备虚拟化(19)
  • 【项目管理】第12章 项目质量管理-- 知识点整理
  • JavaScript 输入输出语句
  • Docker 部署 Kafka 完整指南
  • 系统编程3(共享内存/信号量)
  • 【数据结构与算法】——堆(补充)
  • 人的需求更多是动物本能—观《枪王》
  • 计算视觉与数学结构及AI拓展
  • 【家政平台开发(41)】家政平台性能蜕变:性能测试与优化全解析
  • Spring Boot 中应用的设计模式
  • Spring Security + JWT 实现前后端分离权限控制实战教程
  • 以总理称将全面控制加沙,对伊朗保留单方面行动权利
  • 中英举行人工智能对话
  • 中国华能:1-4月新能源装机突破1亿千瓦,利润总额再创新高
  • 央行行长潘功胜主持召开金融支持实体经济座谈会
  • 90后青年学者李海增逝世9个月后文章登上顶刊,同仁缅怀其贡献
  • 甘肃白银煤矿透水事故最新进展:3名被困矿工已无生命体征