每天一颓: 均摊分析, pi函数和KMP算法
资料内容:
https://oi-wiki.org/string/kmp/
很久以前学过,写一些笔记作复习资料
一些概念:
真前缀, 真后缀等等不作介绍
(真前后缀匹配函数)前缀函数(pi函数):
特别规定,
/*
Author: SJ
*/
#include<bits/stdc++.h>
const int N = 1e5 + 10;
using ll = long long;
using ull = unsigned long long;
std::string s1;
int pi[N];
void pi_query(std::string s1) {
for (int i = 1; i < s1.size(); i++) {
for (int j = i; j >= 0; j--) {
if (s1.substr(0, j) == s1.substr(i - j + 1, j)) {
pi[i] = j;
break;
}
}
}
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> s1;
pi_query(s1);
for (int i = 0; i < s1.size(); i++) std::cout << pi[i] << ' ';
return 0;
}
显然可以这样
引理1: 相邻的pi-function最多增加1
证明: 类似LCS的证明, 反证法即可
代码即可优化成
void pi_query(std::string s1) {
for (int i = 1; i < s1.size(); i++) {
for (int j = pi[i - 1] + 1; j >= 0; j--) {
if (s1.substr(0, j) == s1.substr(i - j + 1, j)) {
pi[i] = j;
break;
}
}
}
}
我们介绍amortized analysis(主要是会计方法)说明一下这样计算是
首先if里面的substr函数是雷打不动的
类似dp的思路, 我们可以往前跳转, 详情请看OI-Wiki,
那为什么这样子做直接就把复杂度变成惊人的
void pi_query(std::string s1) {
for (int i = 1; i < s1.size(); i++) {
int j = pi[i - 1];
while (j > 0 && s1[i] != s1[j]) j = pi[j - 1];
if (s1[i] == s1[j]) j++;
pi[i] = j;
}
}
kmp基本上就是前缀函数计算的一个直接应用
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现