字符串从入门到退竞(2)——KMP 算法
约定在文字描述中字符串下标从
前缀函数
对于长
- 若
有相等的真前缀和真后缀(称之为 border), 为其长度的最大值; - 若不存在,
。
字符串的真前缀或真后缀不包括其本身。
例如
计算前缀函数的朴素算法
容易想到对于每个位置进行暴力枚举。
vector<int> prefix_function(const string &s) {
int n = s.length();
vector<int> pi(n);
for (int i = 1; i < n; ++i)
for (int j = i; j >= 0; --j)
if (s.substr(0, j) == s.substr(i - j + 1, j)) {
pi[i] = j;
break;
}
return pi;
}
字符串比较的复杂度是
第一个优化
注意到前缀函数后一个值最多比前一个值多
vector<int> prefix_function(const string &s) {
int n = s.length();
vector<int> pi(n);
for (int i = 1; i < n; ++i)
for (int j = pi[i - 1] + 1; j >= 0; --j)
if (s.substr(0, j) == s.substr(i - j + 1, j)) {
pi[i] = j;
break;
}
return pi;
}
这看似是常数优化,实则不然。
应用势能分析,定义势能函数为
第二个优化
延续第一个优化的思路,我们只需检查字符串的每一个 border 是否可以“扩展”。
字符串
vector<int> prefix_function(string s) {
int n = s.length();
vector<int> pi(n);
for (int i = 1; i < n; ++i) {
int j = pi[i - 1];
while (j > 0 && s[i] != s[j]) j = pi[j - 1];
if (s[i] == s[j]) ++j;
pi[i] = j;
}
return pi;
}
时间复杂度为
这是一个在线算法,在读取数据时立即处理。
KMP 算法
给定文本串
我们构造字符串
vector<int> find_occurrences(string text, string pattern) {
string cur = pattern + '#' + text;
int sz1 = text.size(), sz2 = pattern.size();
vector<int> v;
vector<int> lps = prefix_function(cur);
for (int i = sz2 + 1; i <= sz1 + sz2; i++) {
if (lps[i] == sz2) v.push_back(i - 2 * sz2);
}
return v;
}
字符串的周期
若字符串
统计每个前缀的出现次数
给定长
vector<int> ans(n + 1);
for (int i = 0; i < n; ++i) ++ans[pi[i]];
for (int i = n - 1; i > 0; --i) ans[pi[i - 1]] += ans[i];
for (int i = 0; i <= n; ++i) ++ans[i];
前缀自动机
在 KMP 算法中,前缀函数不会超过模式串
void compute_automaton(string s, vector<vector<int>>& aut) {
s += '#';
int n = s.size();
vector<int> pi = prefix_function(s);
aut.assign(n, vector<int>(26));
for (int i = 0; i < n; ++i) {
for (int c = 0; c < 26; ++c) {
if (i > 0 && 'a' + c != s[i])
aut[i][c] = aut[pi[i - 1]][c];
else
aut[i][c] = i + ('a' + c == s[i]);
}
}
}
时间复杂度可以做到
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】