KMP 算法

概念讲解

什么是 KMP?

KMP 是一种字符串匹配算法,能在 O(n+m)O(n+m) 时间内完成模式匹配。

核心思想

利用已匹配信息,避免重复匹配。

next 数组

定义

next[i] 表示模式串 P[0..i] 的最长相等前后缀长度。

构建

12345678910111213vector<int> buildNext(string pattern) {
    int m = pattern.size();
    vector<int> next(m, 0);
    int j = 0;
    for (int i = 1; i < m; i++) {
        while (j > 0 && pattern[i] != pattern[j]) {
            j = next[j-1];
        }
        if (pattern[i] == pattern[j]) j++;
        next[i] = j;
    }
    return next;
}

KMP 匹配

12345678910111213141516vector<int> kmp(string text, string pattern) {
    vector<int> next = buildNext(pattern);
    vector<int> result;
    int j = 0;
    for (int i = 0; i < text.size(); i++) {
        while (j > 0 && text[i] != pattern[j]) {
            j = next[j-1];
        }
        if (text[i] == pattern[j]) j++;
        if (j == pattern.size()) {
            result.push_back(i - j + 1);
            j = next[j-1];
        }
    }
    return result;
}

时间复杂度

  • 构建 next:O(m)O(m)
  • 匹配:O(n)O(n)
  • 总计:O(n+m)O(n + m)

考点分析

初赛考查方式

  1. 程序阅读: KMP 程序
  2. 编程题: 字符串匹配

常见考点

  • next 数组
  • KMP 匹配过程
  • 循环节

例题精讲

例题 1:next 数组

题目: 求 "ABABC" 的 next 数组。

解答:

next = {0, 0, 1, 2, 0}

练习题

  1. next 数组的含义是什么?
查看答案

next[i] 表示模式串 P[0..i] 的最长相等前后缀长度。

例如:模式串 "ABABC"

  • next[0] = 0("A" 没有相等前后缀)
  • next[1] = 0("AB" 没有相等前后缀)
  • next[2] = 1("ABA" 的最长相等前后缀是 "A")
  • next[3] = 2("ABAB" 的最长相等前后缀是 "AB")
  • next[4] = 0("ABABC" 没有相等前后缀)
  1. KMP 的时间复杂度是多少?
查看答案

KMP 的时间复杂度:

  • 构建 next 数组:O(m)O(m)
  • 匹配:O(n)O(n)
  • 总计:O(n+m)O(n + m)

其中 n 是文本串长度,m 是模式串长度。

  1. 如何用 next 判断循环节?
查看答案

用 next 判断循环节:

如果 n mod (n−next[n−1])=0n \bmod (n - next[n-1]) = 0,则字符串有循环节,循环节长度为 n−next[n−1]n - next[n-1]。

例如:模式串 "ABABAB"

  • next[5] = 4
  • 6 mod (6−4)=6 mod 2=06 \bmod (6 - 4) = 6 \bmod 2 = 0
  • 循环节长度为 2,即 "AB"

易错点

⚠️ 注意:

  1. next 数组的含义
  2. 匹配失败时 j 的回退
  3. KMP 比暴力快很多
  4. 循环节判断:n % (n - next[n-1]) == 0