2021.7.16 字符串讲解
By Zhang_RQ
哈希
对于一个长度为 n 的字符串,其哈希值为 n∑i=1si×basen−imod,其中 base 和 p 自选
判断两个字符串的一个方法是直接判断哈希值是否相等(虽然说有概率出错)。
可以快速算出一个字符串任意子串的哈希值。
具体而言,预处理出前缀哈希值,然后减一减,乘 base 的若干次逆元就可以了。
在 10^5 级别时可能会出现哈希冲突,可以使用双模数。
有种特殊的模数是自然溢出。
KMP
在线性时间中完成字符串匹配的算法
内容:给定一个源串和模式串,求出模式串在源串中出现的次数及出现的位置。
核心思想:减少暴力匹配时的浪费的信息,利用 nxt 数组进行优化
nxt_i 的定义:对于以 i 结尾的前缀,满足最大的"前缀等于后缀"的长度。
nxt 求法:nxt_i=nxt_{i-1} 新加入的字符匹配 +1 ,否则跳 nxt
匹配做法:暴力匹配,失配时跳 nxt 而不是从头开始。
for(ri i=1,j=0;i<=n;i++){
while(j&&s2[j+1]!=s1[i])
j=nxt[i];
if(s2[j+1]==s1[i])
j++;
if(j==m){
ans.push_back(i-m+1);
j=nxt[j];
}
}
Trie树
把节点作为状态,把字母放到边上。
用法:维护若干串,查询一个串是否是这些串的前缀。
void insert(char *s,int id){
int x=rt;
for(ri i=1;s[i];i++){
if(!son[x][s[i]-'a'])
son[x][s[i]-'a']=++cnt;
x=son[x][s[i]-'a'];
}
nd[id]=x;
}
01Trie:把数字当成二进制串插到Trie里。可以实现不少有趣的功能,比如查一个数的前驱后继(有点像平衡树?)。一个比较经典的应用是维护一个数集,每次查询时给定一个数字,要求从数集中选出来一个数,最大化或最小化两个数的异或和。
AC自动机
可以理解为在多个串上的KMP。利用Trie树来维护这些串,nxt数组变为fail指针。
Fail指针的构造思想:
可以直接构造 trie 图以进行多串匹配。
Trie图构建的代码:
il void fail(){
queue<int> q;
for(ri i=0;i<26;i++)
if(son[rt][i]){
q.push(son[rt][i]);
fail[son[rt][i]]=rt;
}
while(!q.empty()){
int x=q.front();
q.pop();
for(ri i=0;i<26;i++){
if(son[x][i]){
fail[son[x][i]]=son[fail[x]][i];
q.push(son[x][i]);
}
else
son[x][i]=son[fail[x]][i];
}
}
for(ri i=1;i<=cnt;i++)
tot[fail[i]]++;
}
Manacher
用于求解最长回文子串的算法,线性。
思想:利用之前的已知信息来优化:
- 维护当前最长的回文串和其回文中心
- 对于一个新加入的位置,从关于会问中心对称的位置继承答案。
- 这样每次更新答案的时候都是本质不同的回文串,复杂度自然就是线性的。
在字符之间添加 '#' 以处理回文中心不在字符上的情况。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次 .NET某旅行社酒店管理系统 卡死分析
· 长文讲解 MCP 和案例实战
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· Android编译时动态插入代码原理与实践
· 解锁.NET 9性能优化黑科技:从内存管理到Web性能的最全指南
· 一天 Star 破万的开源项目「GitHub 热点速览」
· 别再堆文档了,大模型时代知识库应该这样建
· 瞧瞧别人家的日期处理,那叫一个优雅!
· C#/.NET/.NET Core技术前沿周刊 | 第 35 期(2025年4.14-4.20)
· 使用TypeScript开发微信小程序(云开发)-入门篇