跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ KMP 算法详解:高效字符串查找实现

KMP 算法是一种高效的字符串匹配算法,通过将时间复杂度从 O(n×m) 优化至 O(n+m),解决了暴力匹配效率低下的问题。其核心在于构建前缀表(next 数组),利用已匹配部分的信息确定模式串的回退位置,避免主串指针回溯。文章详细阐述了前缀表定义、最长相等前后缀计算逻辑以及 next 数组的两种实现方式,并提供了完整的 C++ 代码示例,涵盖 next 数组构建与匹配过程,适用于算法面试及实际工程开发中的子串查找场景。

指针猎手发布于 2026/3/16更新于 2026/6/2043 浏览

KMP 算法详解:从暴力匹配到高效字符串查找

在经典字符串查找问题中,要求在一个字符串(haystack)中查找另一个字符串(needle)首次出现的位置。如果用暴力法,时间复杂度是 O(n×m),但在实际工程和面试中,我们更希望用 O(n + m) 的高效算法 —— 这就是 KMP(Knuth-Morris-Pratt)算法。

本文将带你从零彻底搞懂 KMP,包括:

  • 为什么需要 KMP?
  • 什么是前缀表(Prefix Table)?
  • 如何构建 next 数组?
  • 如何用 next 数组进行匹配?
  • 两种主流实现方式(前缀表减一 vs 不减一)

一、为什么需要 KMP?—— 暴力匹配的痛点

假设:

  • haystack = "aabaabaafa"
  • needle = "aabaaf"

暴力匹配过程如下:

  1. 从 haystack[0] 开始匹配,前 5 个字符都匹配成功(a a b a a)
  2. 到第 6 个字符时,haystack[5] = 'b',needle[5] = 'f' → 不匹配
  3. 暴力法会回退到 haystack[1] 重新开始匹配

但注意:前面已经匹配了 'aabaa',其中包含重复信息(如前缀 'aa' 和后缀 'aa' 相同)。 KMP 的核心思想就是:利用已匹配部分的信息,避免从头开始匹配!

二、KMP 的灵魂:前缀表(Prefix Table)

✅ 什么是前缀?什么是后缀?

对字符串 "aabaaf":

  • 前缀:不包含最后一个字符的所有以第一个字符开头的连续子串 → "a", "aa", "aab", "aaba", "aabaa"
  • 后缀:不包含第一个字符的所有以最后一个字符结尾的连续子串 → "f", "af", "aaf", "baaf", "abaaf"

⚠️ 注意:前缀 ≠ 子串,必须从头开始;后缀必须到尾结束。

✅ 什么是最长相等前后缀?

对每个位置 i,计算 s[0..i] 的最长相等前后缀长度。

例如:

子串最长相等前后缀长度
"a"无0
"aa""a" == "a"1
"aab"无0
"aaba""a" == "a"1
"aabaa""aa" == "aa"2
"aabaaf"无0

所以前缀表为:[0, 1, 0, 1, 2, 0]

🎯 前缀表的作用:当匹配失败时,告诉我们模式串应该跳到哪个位置继续匹配。

三、next 数组:前缀表的两种实现方式

在 KMP 中,通常用 next 数组来存储前缀表。但有两种主流实现:

方式 1️⃣:前缀表不减一(直接使用)
  • next[i] = s[0..i] 的最长相等前后缀长度
  • 示例:"aabaaf" → next = [0, 1, 0, 1, 2, 0]
方式 2️⃣:前缀表统一减一(右移一位)
  • next[0] = -1,其余 next[i] = 原前缀表 [i-1]
  • 示例:"aabaaf" → next = [-1, 0, -1, 0, 1, -1]

💡 两种方式都能正确工作,只是匹配时的指针逻辑不同。 本文将分别讲解两种实现!

四、方式一:前缀表不减一(推荐初学者)

步骤 1:构建 next 数组
void getNext(int* next, const string& s) {
    int j = 0; // j 表示前缀末尾
    next[0] = 0;
    for (int i = 1; i < s.size(); i++) {
        // 前后缀不相同,j 回退
        while (j > 0 && s[i] != s[j]) {
            j = next[j - 1];
        }
        // 前后缀相同,j 向前移动
        if (s[i] == s[j]) {
            j++;
        }
        next[i] = j; // 记录当前最长相等前后缀长度
    }
}
步骤 2:使用 next 数组匹配
int strStr(string haystack, string needle) {
    if (needle.empty()) return 0;
    vector<int> next(needle.size());
    getNext(next.data(), needle);
    int j = 0;
    for (int i = 0; i < haystack.size(); i++) {
        while (j > 0 && haystack[i] != needle[j]) {
            j = next[j - 1];
        }
        if (haystack[i] == needle[j]) {
            j++;
        }
        if (j == needle.size()) {
            return i - j + 1;
        }
    }
    return -1;
}

目录

  1. KMP 算法详解:从暴力匹配到高效字符串查找
  2. 一、为什么需要 KMP?—— 暴力匹配的痛点
  3. 二、KMP 的灵魂:前缀表(Prefix Table)
  4. ✅ 什么是前缀?什么是后缀?
  5. ✅ 什么是最长相等前后缀?
  6. 三、next 数组:前缀表的两种实现方式
  7. 方式 1️⃣:前缀表不减一(直接使用)
  8. 方式 2️⃣:前缀表统一减一(右移一位)
  9. 四、方式一:前缀表不减一(推荐初学者)
  10. 步骤 1:构建 next 数组
  11. 步骤 2:使用 next 数组匹配
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Linux 核心 IO 模型深析:非阻塞 IO 与多路转接实现
  • Android 滑动冲突解决技巧详解
  • 渗透测试具体详细检测方法
  • 8 款主流公文 AI 写作工具深度测评与对比
  • Llama-3.2-3B 本地部署指南:Ollama + Docker 快速运行
  • AI 编程工具深度评测:Trae 3.0, Cursor, Qoder 等五大方案对比
  • 网络、运维与安全基础技术词汇汇总
  • UI-UX-Pro-Max Skill 完全指南:在 Claude Code 中实现 AI 辅助 UI 设计
  • Python 实现 B 站充电视频下载工具
  • AI 视频生成模型构建、实现与调试指南
  • 百度否认大模型泡沫论,AI 业务持续盈利
  • QQ 机器人 Webhook 方式简易部署教程
  • OpenClaw 机器人抓取平台搭建全流程详解
  • IOPaint 开源 AI 图像修复工具使用指南
  • Axum:Rust 生态中的高性能 Web 框架实战
  • Redis IO 多路复用模型详解
  • Python AI 大模型部署指南:本地运行、API 服务与 Docker 封装
  • 2026 AI 编码工具深度对比:Claude Code、Cursor 与 GitHub Copilot 选型指南
  • AI Agent 实战:生产级框架搭建与落地指南
  • Android Studio 使用 Gemini 进行 AI 编程

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online