字符串存储与 BF、KMP 匹配算法

字符串存储与 BF、KMP 匹配算法

字符串匹配的目标是在主串 S 中查找模式串 P 的首次出现位置。算法性能的关键在于:主串发生失配后,能否复用已经比较过的信息。

定长顺序字符串

一种教材式字符串结构用第 0 个位置保存长度,用 S[1..len] 保存字符:

text 复制代码
S[0]     = length
S[1..n]  = characters

这种结构不等同于 C 字符串,不能直接套用 strlen 或 \0 终止规则。拼接时必须先检查容量,匹配函数也必须统一返回值约定。

BF 算法

BF 从每个可能起点重新比较模式串:

cpp 复制代码
for (int start = 0; start + m <= n; ++start) {
    int j = 0;
    while (j < m && text[start + j] == pattern[j]) ++j;
    if (j == m) return start;
}
return -1;

主串长度为 n、模式串长度为 m 时,最坏时间复杂度为 O(nm),额外空间为 O(1)。BF 代码简单,短字符串场景中常数开销较低。

KMP 的核心:前缀函数

若 P[0..j-1] 已经匹配,P[j] 失配,不必让主串指针回退。模式串的某个最长相等前缀和后缀可以继续参与匹配。

定义 next[j] 表示模式串失配时的回退位置。构造时维护当前候选前缀长度:

cpp 复制代码
next[0] = -1;
int i = 0, j = -1;
while (i < m) {
    if (j == -1 || pattern[i] == pattern[j]) {
        ++i;
        ++j;
        next[i] = j;
    } else {
        j = next[j];
    }
}

匹配过程为:

cpp 复制代码
while (i < n && j < m) {
    if (j == -1 || text[i] == pattern[j]) {
        ++i;
        ++j;
    } else {
        j = next[j];
    }
}
return j == m ? i - m : -1;

主串指针只向前移动,模式串指针通过 next 回退。预处理为 O(m),匹配为 O(n),总复杂度为 O(n+m),额外空间为 O(m)。

nextval 优化

若回退后比较的字符与刚才失配字符相同,则该比较必然再次失败,可以继续跳过:

cpp 复制代码
nextval[i] = pattern[i] == pattern[next[i]]
           ? nextval[next[i]]
           : next[i];

nextval 不改变渐进复杂度,但能减少重复字符模式下的无效比较。

工程注意事项

  • 明确字符下标从 0 还是从 1 开始。
  • 明确失败返回 -1、0 还是其他值。
  • 空模式串需要单独定义语义。
  • Unicode 字符串不能简单按字节等同于字符。
  • 大文本重复匹配时,应复用模式串预处理结果。

KMP 的本质是把模式串的自相似性编码为回退表,使匹配过程不重复扫描已经确认过的主串字符。

相关推荐
小超人诞生日记1 小时前
Linux:环境变量 & 进程虚拟地址空间
linux·算法
小白起 v1 小时前
【算法学习 · 01】深入理解大 O 表示法:从「能跑就行」到「专业评估」算法性能
算法
梦帮科技1 小时前
脑机接口(BCI)与神经系统安全:EEG 神经电信号欺骗注入、神经闭环解码算法与生物黑客反制
算法·安全
老徐聊GEO1 小时前
把“安徽“写进题面之后:多平台AI推荐名单的区域扰动测量(2026)
前端·人工智能·算法·geo优化
人工智能培训1 小时前
具身智能:让人工智能拥有物理世界感知能力
大数据·人工智能·学习·算法·机器学习
果壳science1 小时前
张祥前最新研究成果登上SCI期刊!
笔记·嵌入式硬件·算法·硬件工程·几何学
Rabitebla1 小时前
【Linux 底层原理】工具篇(一):掌握 Ubuntu apt,让软件安装与管理更简单
linux·笔记·算法·ubuntu
碧海银沙音频科技研究院2 小时前
基于炬芯ATS308X的DNN全连接神经网络手写数字识别系统设计
人工智能·深度学习·算法
stolentime2 小时前
SOS DP学习笔记
c++·笔记·学习·算法·贪心算法·动态规划·二进制