线性结构之字符串

#字符串

基本概念

  1. :特殊的线性表,数据元素为字符
  2. 空串:长度为零的串""
  3. 空格串:仅由空格组成的串" "" "
  4. 子串:串中任意连续字符组成的序列
  5. 主串:包含子串的串
  6. 模式匹配:在主串中定位子串(模式串)的操作

一、朴素模式匹配算法

朴素模式匹配算法是最直观的字符串匹配方法,其核心思想是:将模式串在主串中逐个位置进行比对,如果当前字符匹配成功,则两个指针同时向后移动一位;否则,将模式串的指针移回起始位置,主串的指针向后移动一位,再次尝试匹配。

时间复杂度:O(m*n),其中m是模式串长度,n是主串长度。

朴素算法匹配过程(主串S: “ABABABABCABAAB”,模式串P: “ABABC”)

  1. 从S[0]开始匹配

    • S[0]=‘A’ vs P[0]=‘A’ → 匹配
    • S[1]=‘B’ vs P[1]=‘B’ → 匹配
    • S[2]=‘A’ vs P[2]=‘A’ → 匹配
    • S[3]=‘B’ vs P[3]=‘B’ → 匹配
    • S[4]=‘A’ vs P[4]=‘C’ → 不匹配
    • 不匹配,主串指针后移1位到S[1],模式串指针回退到P[0]
  2. 从S[1]开始匹配

    • S[1]=‘B’ vs P[0]=‘A’ → 不匹配
    • 不匹配,主串指针后移1位到S[2],模式串指针回退到P[0]
  3. 从S[2]开始匹配

    • S[2]=‘A’ vs P[0]=‘A’ → 匹配
    • S[3]=‘B’ vs P[1]=‘B’ → 匹配
    • S[4]=‘A’ vs P[2]=‘A’ → 匹配
    • S[5]=‘B’ vs P[3]=‘B’ → 匹配
    • S[6]=‘A’ vs P[4]=‘C’ → 不匹配
    • 不匹配,主串指针后移1位到S[3],模式串指针回退到P[0]
  4. 从S[3]开始匹配

    • S[3]=‘B’ vs P[0]=‘A’ → 不匹配
    • 不匹配,主串指针后移1位到S[4],模式串指针回退到P[0]
  5. 从S[4]开始匹配

    • S[4]=‘A’ vs P[0]=‘A’ → 匹配
    • S[5]=‘B’ vs P[1]=‘B’ → 匹配
    • S[6]=‘A’ vs P[2]=‘A’ → 匹配
    • S[7]=‘B’ vs P[3]=‘B’ → 匹配
    • S[8]=‘C’ vs P[4]=‘C’ → 匹配
    • 匹配成功!起始位置为4

朴素算法总结:共进行了5次匹配尝试,匹配成功时起始位置为4。

二、KMP算法

KMP算法通过预处理模式串,构建一个next数组(部分匹配表),记录模式串中每个位置之前的子串中,最长相同前缀后缀的长度。当发生不匹配时,利用next数组决定模式串的移动位置,避免了主串指针的回溯。

时间复杂度:O(m+n),其中m是模式串长度,n是主串长度。

1. 构建next数组(模式串P: “ABABC”)

模式串:A B A B C

位置字符前缀后缀最长相同前缀后缀长度next值
0A-1
1BAB0
2AA, ABA, BAA (长度1)1
3BA, AB, ABAB, AB, BABAB (长度2)2
4CA, AB, ABA, ABABC, BC, ABC, BABC0

next数组:[-1, 0, 1, 2, 0]

通常实现时,next[0] = -1,用于特殊处理第一个字符就不匹配的情况。

2. KMP算法匹配过程(主串S: “ABABABABCABAAB”,模式串P: “ABABC”)

  • KMP 的核心思想

    • 匹配失败时,主串指针 i 不回溯,只调整模式串指针 j 的位置
    • 利用已匹配的部分字符的前缀和后缀的公共信息,让 j 移动到「能复用已匹配内容」的位置,避免重复比对(模式串指针 j 在失配时根据 next[j-1] 跳转)
  • 关键:前缀函数(next 数组)

    • next 数组本质是模式串的自相关性。它记录了:如果在位置 j 失配,那么模式串可以“安全地”滑动到 next[j-1] 位置继续匹配,因为前面的 next[j-1] 个字符已经和主串对齐。
    • 前缀:模式串中,除最后一个字符外,从开头到任意位置的子串(比如 “ABC” 的前缀是 “A”、“AB”)
    • 后缀:模式串中,除第一个字符外,从任意位置到结尾的子串(比如 “ABC” 的后缀是 “C”、“BC”)
    • next数组的定义是:next[j]表示模式串中长度为j+1的子串(即从索引0到j的子串)的最长公共前后缀长度。当匹配失败时,我们已经匹配了前j个字符(索引0到j-1),所以我们需要使用next[j-1]来决定j应该更新为多少。
  • KMP 匹配过程(核心逻辑)

    • 先计算模式串 P 的 next 数组
    • 用指针 i 遍历主串 S(不回溯),指针 j 遍历模式串 P
    • 若 S[i] == P[j],则 i++、j++,继续比对
    • 若 S[i] != P[j]:
    • 若 j > 0,则 j = next[j-1](利用 next 数组回退 j,复用已匹配的内容)
    • 若 j == 0,则 i++(模式串第一个字符就不匹配,主串指针后移)
    • 当 j ==len(P)时,匹配成功,返回起始位置 i-j;否则返回 -1
  1. 初始化

    • i = 0(主串指针),j = 0(模式串指针)
    • next数组:[-1, 0, 1, 2, 0]
  2. 匹配过程

    • i=0, j=0:S[0]=‘A’ vs P[0]=‘A’ → 匹配 → i=1, j=1

    • i=1, j=1:S[1]=‘B’ vs P[1]=‘B’ → 匹配 → i=2, j=2

    • i=2, j=2:S[2]=‘A’ vs P[2]=‘A’ → 匹配 → i=3, j=3

    • i=3, j=3:S[3]=‘B’ vs P[3]=‘B’ → 匹配 → i=4, j=4

    • i=4, j=4:S[4]=‘A’ vs P[4]=‘C’ →不匹配

      • j = next[j-1] = next[3] = 2
      • 现在比较S[4]=‘A’ vs P[2]=‘A’ → 匹配 → i=5, j=3
    • i=5, j=3:S[5]=‘B’ vs P[3]=‘B’ → 匹配 → i=6, j=4

    • i=6, j=4:S[6]=‘A’ vs P[4]=‘C’ →不匹配

      • j = next[j-1] = next[3] = 2
      • 现在比较S[6]=‘A’ vs P[2]=‘A’ → 匹配 → i=7, j=3
    • i=7, j=3:S[7]=‘B’ vs P[3]=‘B’ → 匹配 → i=8, j=4

    • i=8, j=4:S[8]=‘C’ vs P[4]=‘C’ →匹配成功

      • j = 5 == len§,匹配成功
      • 起始位置 = i - j + 1 = 8 - 5 + 1 = 4

KMP算法总结:共进行了3次匹配尝试(而非5次),匹配成功时起始位置为4。

解释:

  1. 为什么是next[j-1]而不是next[j]?

    • 当匹配失败时(即S[i] != P[j]),我们需要将j更新为一个值,使得模式串能够"跳过"一些已经匹配的字符,避免重复比较。*
    • j=4表示我们已经匹配了"ABAB"(索引0-3),现在匹配失败
    • 我们需要找到"ABAB"的最长公共前后缀长度,这个长度由next[3]给出(因为"ABAB"是长度为4的子串,对应next[3])
    • next[3] = 2表示"ABAB"的最长公共前后缀长度为2(即"AB")
    • 我们应该使用next[j-1] = next[3] = 2,而不是next[j] = next[4] = 0
    • 所以,我们应该将j更新为2,表示模式串可以向右移动2位,让"AB"与主串的当前字符对齐
  2. 为什么可以跳过前两个字符?

    • 我们已知主串的这部分是"ABAB"

    • 后缀"AB" = 前缀"AB"

    • 所以主串的后两个字符"AB"一定等于模式串的前两个字符"AB"

    • 不需要重新比较,直接从模式串的第3个字符开始

  3. KMP 算法匹配过程的核心逻辑

  • next = [-1, 0, 1, 2, 0]
  • 匹配到i=4, j=4时:S[4]='A' ≠ P[4]='C'
    • j > 0j = next[3] = 2
    • 下一轮比较S[4]P[2](即'A' == 'A',继续)
  • 最终在i=9, j=5时:j == len(P)→ 匹配成功,起始位置 =9 - 5 = 4

三、两种算法对比

特性朴素匹配算法KMP算法
匹配过程每次不匹配都回溯主串指针不回溯主串指针,利用next数组跳过无效匹配
匹配次数5次3次
时间复杂度O(m*n)O(m+n)
实现复杂度简单较复杂(需构建next数组)
优势代码简单直观高效,适用于大规模数据匹配

四、KMP算法的核心思想

KMP算法的核心在于:当匹配失败时,我们不把文本串的比较指针回溯,而是根据已经匹配过的内容,将模式串的指针"智能地"向前跳转

在本例中,当在S[4]处匹配失败(S[4]=‘A’ vs P[4]=‘C’)时,KMP算法利用next数组得知P[0…2] = "ABA"与S[2…4] = "ABA"匹配,因此可以直接将模式串的指针移动到j=2的位置,继续比较S[4]和P[2],避免了主串指针的回溯。

这种"智能跳转"使得KMP算法在最坏情况下也能保持线性时间复杂度,而朴素算法在最坏情况下需要O(m*n)时间。

五、总结

  • 朴素匹配算法思路简单,但效率低下,尤其在模式串有重复字符时
  • KMP算法通过预处理模式串构建next数组,避免了不必要的比较,大大提高了匹配效率
  • 在实际应用中,特别是处理大规模数据时,KMP算法是更优的选择

通过这个例子,我们可以清晰地看到KMP算法如何利用已匹配的信息,避免了朴素算法中重复的比较工作,从而提高了匹配效率。

你总结得非常准确!这是KMP 算法匹配过程的核心逻辑,完全正确。下面我将你的总结稍作整理,并补充一些细节说明,使其更清晰、严谨,便于理解和实现。


✅ KMP 匹配过程(核心逻辑)

步骤 1:预处理 —— 构建next数组

  • 对模式串P预处理,生成next数组。
  • next[j]表示:子串P[0..j]的最长相等真前缀与真后缀的长度
  • 注意:不同教材对next数组的定义略有差异(有的从 0 开始,有的从 -1 开始),但核心思想一致。

常见两种定义:

  • 定义 A(常用)next[0] = -1next[j]表示当P[j]失配时,j应跳转到的位置。
  • 定义 Bnext[j]表示P[0..j-1]的最长公共前后缀长度(此时next[0] = 0)。

我们以下采用定义 A(带 -1),因为它在代码中更简洁。


步骤 2:匹配主串 S 与模式串 P

初始化:

  • i = 0:主串 S 的指针(永不回溯
  • j = 0:模式串 P 的指针

循环直到i >= len(S)

情况 1:字符匹配
if S[i] == P[j]: i += 1 j += 1
  • 双指针同步前进。
情况 2:字符不匹配
else: if j > 0: j = next[j - 1] // 利用已匹配信息,j 回退,i 不动 else: // j == 0,即模式串首字符就不匹配 i += 1 // 主串指针后移,j 保持为 0

🔍 关键点:只有当 j == 0 且失配时,才移动 i;否则只调整 j。

情况 3:匹配成功
if j == len(P): 找到匹配!起始位置 = i - j (可选择继续查找:j = next[j - 1] 继续匹配)

📌 示例回顾(S = “ABABABABCABAAB”, P = “ABABC”)

  • next = [-1, 0, 1, 2, 0]
  • 匹配到i=4, j=4时:S[4]='A' ≠ P[4]='C'
    • j > 0j = next[3] = 2
    • 下一轮比较S[4]P[2](即'A' == 'A',继续)

最终在i=9, j=5时:j == len(P)→ 匹配成功,起始位置 =9 - 5 = 4


✅ 为什么这个逻辑正确?

  • 主串指针 i 永不回溯→ 时间复杂度 O(n)
  • next 数组保证了“最大可能复用”已匹配部分→ 避免重复比较
  • j = next[j-1]是因为:当前已匹配的是P[0..j-1],其最长公共前后缀长度决定了 j 能跳到哪里

🧠 小贴士:如何记忆?

匹配就一起走,不匹配就看 next;j 能退就退,退不了就 i 走


✅ 最终结论

你给出的总结完全正确,是 KMP 匹配阶段的标准流程。只要配合正确的next数组构建方法,就能实现高效的字符串匹配。

如果需要,我也可以提供完整的 Python/C++ 实现代码!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1201650.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

校招失败后,在小公司熬了 2 年终于进了百度,竭尽全力....

其实两年前校招的时候就往百度投了一次简历,结果很明显凉了,随后这个理想就被暂时放下了,但是这个种子一直埋在心里这两年除了工作以外,也会坚持写博客,也因此结识了很多优秀的小伙伴,从他们身上学到了特别…

三相无刷交流电机Simulink闭环控制-PART-三相无刷电机-VA解析

三相无刷交流电机Simulink闭环控制-PART-三相无刷电机-VA解析三相无刷交流电机Simulink闭环控制-PART-三相无刷电机-VA解析 关键词:AMC B40A40AC simulink 三相无刷交流电机 一、问题分析 在高校或工程自动化实验中,…

2025年六大论文引用工具评测:智能规范推荐

核心工具对比速览 工具名称 核心优势 适用场景 处理速度 AiBiye 智能识别引用格式,自动匹配规范 学术论文初稿 3-5秒/页 AiCheck 深度检测引用缺失,精准定位问题 论文终稿检查 10秒/篇 AskPaper 多语言引用规范支持 国际期刊投稿 5-8秒/页…

5年华为外包,外包究竟怎么样....

最近身边很多人进了外包或者被问到进到外包公司怎么样,感觉大家对外包公司不是很了解,也有一些误解,我们看看过来人怎么说。 5年外包时光 我曾是华为外包软件测试员工,就职于东莞松山湖,2017年9月12号入职&#xff0c…

2025最佳论文引用工具:自动排版与AI推荐

核心工具对比速览 工具名称 核心优势 适用场景 处理速度 AiBiye 智能识别引用格式,自动匹配规范 学术论文初稿 3-5秒/页 AiCheck 深度检测引用缺失,精准定位问题 论文终稿检查 10秒/篇 AskPaper 多语言引用规范支持 国际期刊投稿 5-8秒/页…

导师推荐!8款AI论文工具测评:本科生写毕业论文必备

导师推荐!8款AI论文工具测评:本科生写毕业论文必备 2026年AI论文工具测评:为何值得一看? 随着人工智能技术的不断进步,AI论文工具已经成为本科生撰写毕业论文的重要辅助。然而,市面上的工具种类繁多&#x…

论文引用工具Top6:2025自动规范生成指南

核心工具对比速览 工具名称 核心优势 适用场景 处理速度 AiBiye 智能识别引用格式,自动匹配规范 学术论文初稿 3-5秒/页 AiCheck 深度检测引用缺失,精准定位问题 论文终稿检查 10秒/篇 AskPaper 多语言引用规范支持 国际期刊投稿 5-8秒/页…

IREE的Flow方言如何实现Attention高效计算QKV?

一、问题动机:为什么 QKV 是 必须 做 Multi-output Fusion 的场景 以 Transformer 中最典型的结构为例: [ Q = X W_Q,\quad K = X W_K,\quad V = X W_V ] 朴素实现的问题 在“算子级”视角下,这是 三个独立 MatMul:…

智能引用工具排名2025:6大平台精准推荐

核心工具对比速览 工具名称 核心优势 适用场景 处理速度 AiBiye 智能识别引用格式,自动匹配规范 学术论文初稿 3-5秒/页 AiCheck 深度检测引用缺失,精准定位问题 论文终稿检查 10秒/篇 AskPaper 多语言引用规范支持 国际期刊投稿 5-8秒/页…

键盘出口美欧合规认证指南FCC/CE

键盘出口美国、欧盟需针对性完成合规认证,关乎清关、平台上架及市场准入,有线 / 无线产品要求不同,核心要点如下: 一、美国市场: 1. FCC 认证为强制核心。有线键盘(USB/PS2 接口)做 FCC-SDoC …

价值投资中的新型高效储氢材料技术前景

价值投资中的新型高效储氢材料技术前景 关键词:价值投资、新型高效储氢材料、技术前景、氢能利用、能源存储 摘要:本文围绕价值投资视角下新型高效储氢材料技术的前景展开探讨。首先介绍了价值投资关注该技术的背景,包括目的、预期读者等内容…

2026.1.22

今天进行了spark实验的实验三

叉车实训模拟哪家性价比最高

叉车实训模拟哪家性价比最高榜单解析开篇总起在叉车操作培训领域,随着企业对员工技能要求的提升,叉车实训模拟的需求日益增长。据市场调研机构数据显示,该行业年复合增长率达 15%。然而市场上厂商众多,质量参差不齐,采…

Simulink:FY2300 信号源怎么控-PART-FeelTech-RS232

Simulink:FY2300 信号源怎么控-PART-FeelTech-RS232Simulink:FY2300 信号源怎么控-PART-FeelTech-RS232 关键词:RS232、Simulink、串口协议、信号源控制、FY2300、仪器通信 技术场景 高校自动化实验中,需要在 MATL…

滑雪头盔ASTM F2040-18 CPC/GCC认证指南

北美滑雪头盔认证避坑指南ASTM F2040CPCGCC一报告两证通关攻略 一、 为什么必须认证? 1.亚马逊强制要求:销售滑雪头盔必须提供ASTM F2040测试报告CPC证书(儿童款)或GCC证书(成人款),否则直接下架…

完整教程:Flutter 中, Flame + flame_forge2d世界坐标和屏幕坐标对齐

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

即插即用系列 | CVPR 2025 SegMAN: Mamba与局部注意力强强联合,多尺度上下文注意力的新SOTA

论文题目:SegMAN: Omni-scale Context Modeling with State Space Models and Local Attention for Semantic Segmentation 论文作者:Yunxiang Fu, Meng Lou, Yizhou Yu (The University of Hong Kong) 代码地址:https:// github.com/yunxian…

自行车出口美国GCC认证16 CFR 1512标准解读

自行车出口美国必看!16 CFR 1512认证攻略! 一、为什么必须做GCC认证?亚马逊新规:成人/儿童/电动自行车上架美国站必须提供16 CFR 1512测试报告GCC证书!无证产品下架流量限流最高罚10万美元。二、超全办理流程&#xff…

1.22随笔

其实昨天就大概看了下 Hive 的基础概念,知道它是用 SQL 来处理大数据的工具,不用写复杂的代码,刚好我之前接触过数据库的增删改查,上手起来不算太费劲。 今天还简单了解了下 Hive 的分区表,因为后续处理大数据的时…

AT_arc108_e [ARC108E] Random IS

考虑一个 \(O(n^3)\) 做法。设 \(f_{i, j}\) 为取到区间 \([i, j]\) 且 \(i, j\) 两端点都被取到的椅子数量期望是多少,最后用 \(n\) 减一下就可以了,转移就是枚举此时新选择的一个点 \(k\),然后你注意到 \([i, k -…