KMP 算法
字符串匹配是算法中的经典问题。给定主串 S 和模式串 P,我们需要找到 P 在 S 中首次出现的位置。
暴力匹配思路
最直观的做法是枚举主串的每一个位置作为起点,逐个字符比较。一旦遇到不匹配,模式串就回到开头重新尝试。这种方法逻辑简单,但在长文本场景下效率较低,时间复杂度为 O(m*n)。
for(int i = 1; i <= m; i++) { // 枚举主串起点
bool flag = true;
for(int j = 1; j <= n; j++) {
if(S[i + j - 1] != P[j]) {
flag = false;
break;
}
}
}
优化原理
仔细观察会发现,当匹配失败时,模式串本身往往包含重复的前缀和后缀。我们不需要把模式串完全重置到开头,而是可以直接跳过已经确认匹配的部分。这就是 KMP 的核心思想。

为了实现这一跳跃,我们需要预处理一个 next 数组(代码中常记为 ne)。
next 数组的含义
next[i] 表示以 i 结尾的子串中,最长相等前后缀的长度。也就是说,如果 next[i] = j,意味着 P[1...j] 和 P[i-j+1...i] 是相同的。
构建 next 数组的过程其实也是一个自匹配的过程:
// 计算 next 数组
for(int i = 2, j = 0; i <= n; i++) {
while(j && P[i] != P[j + 1]) j = ne[j];
if(P[i] == P[j + 1]) j++;
ne[i] = j;
}
这里 j 代表当前匹配到的前缀长度。如果不匹配,就回退到 ne[j] 继续尝试,直到匹配成功或 j 归零。
匹配过程
有了 next 数组,匹配主串时就不需要回溯指针 i,只需调整 j 即可。这样整体时间复杂度降为 O(m+n)。


