字符串存储与 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 的本质是把模式串的自相似性编码为回退表,使匹配过程不重复扫描已经确认过的主串字符。

相关推荐
唐墨12314 分钟前
linux kernel 比较数据大小的宏定义
linux·算法
拂拉氏1 小时前
【知识讲解-题目讲解】 统计满足K约束的子字符串数量2 (滑动窗口+前缀和+二分查找+分析)
算法·前缀和·二分查找·滑动窗口
通信小呆呆5 小时前
电子战抗干扰技术:当“不被干扰”成为一种系统
算法·通信·mimo·isac
笑容掩饰我的失落5 小时前
区块链从小白到精通(八):从零实现一个标准 ERC-20 代币(完整可运行代码)
算法·区块链·php·智能合约·哈希算法
Severus_black6 小时前
【C++初阶】Stack、Queue算法题大练兵!
c语言·c++·算法·stl
2601_967979129 小时前
机器学习必修课:经典算法与Python实战
python·算法·机器学习·实战·课程
程序猿打工仔9 小时前
计算机基础(C语言)考编、专技岗
c语言·开发语言·算法
通信小呆呆9 小时前
电子战干扰技术:从“蛮力压制”到“精准欺骗”,再到“认知博弈”
算法·通信·isac
老师我太想进步了20269 小时前
【数据结构-6】算法美学之单链表(1)
数据结构·算法
希望我万事顺遂10 小时前
力扣hot100-滑动窗口最大值
数据结构·算法·leetcode