news 2026/7/17 4:07:45

算法总结:字符串算法(一)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法总结:字符串算法(一)

背景

复健次日,本来想接着做连通图,结果调一个题调了3h才发现自己把i–写成i++了,AI也没发现,气得本人想当场退役,只好看看字符串来压压惊。

一、字符串哈希

模板:P3370
判断两个字符串是否相同,H a s h HashHash是个不错的方法。
试想有1 e 9 1e91e9个不同的数字,从中选出1 e 6 1e61e6个,如何判断有多少个不同的数?
我们可以将这些数分别对1 e 6 1e61e6取模,以此判断两数是否相同。
以此类推,对于字符串,我们可以把它类比为一个B BB进制数,通过逐位累加取模便可得到它的H a s h HashHash函数。
如果两个字符串的H a s h HashHash函数不同,那么它们一定不同,若相同,则它们不一定相同。
这就产生了问题:两个不同的字符串构成了相同的H a s h HashHash函数,产生了相撞。
对于最基础的哈希,有以下几种办法避免相撞:
1.将进制B BB和模数M MM调为质数(不会证明)
2.用双哈希(显而易见)
3.相信自己是天命之子(慎用)

代码

#include<bits/stdc++.h>usingnamespacestd;#definelllonglong#defineB233#defineM100000007intgethash(string s){intans=0;for(charc:s){ans=(ans*B+c)%M;}returnans;}set<int>s;signedmain(){intn;string st;cin>>n;for(inti=1;i<=n;i++){cin>>st;s.insert(gethash(st));}cout<<s.size();return0;}

二、字典树

模板:P8036
字典树(T r i e TrieTrie),是一棵这样的树:

显然,每个结点都代表一个字符,这样的结构能很好地解决前缀问题。
构建字典树的过程中,需要维护三个变量:
1.i d x idxidx:字典树的结点数;
2.a [ p o s ] [ c ] a[pos][c]a[pos][c]:表示c cc字符在第p o s pospos位置时其子结点的位置;
3.c n t [ p o s ] cnt[pos]cnt[pos]:记录第p o s pospos位置出现过的字符数量。
建树时,若当前位置无字符,则更新idx,新建结点;
查询时,若当前位置无字符,则说明没有字符串以它为前缀;反之,则有c n t [ p o s ] cnt[pos]cnt[pos]个字符串以它为前缀。
另外,由于空间限制,本题需要离散化。

代码

#include<bits/stdc++.h>usingnamespacestd;#defineN3000006inta[N][62],cnt[N];intT,n,q,idx;string s;intfind(charc){//离散化if(isdigit(c))returnc-'0';if(isupper(c))returnc-'A'+10;if(islower(c))returnc-'a'+36;}voidinsert(string s){intpos=0;for(charch:s){intc=find(ch);if(!a[pos][c])a[pos][c]=++idx;pos=a[pos][c];cnt[pos]++;}}intquery(string s){intpos=0;for(charch:s){intc=find(ch);if(!a[pos][c])return0;pos=a[pos][c];}returncnt[pos];}intmain(){cin>>T;while(T--){idx=0;cin>>n>>q;for(inti=1;i<=n;i++){cin>>s;insert(s);}for(inti=1;i<=q;i++){cin>>s;cout<<query(s)<<endl;}for(inti=0;i<=idx;i++){for(intj=0;j<62;j++)a[i][j]=0;}for(inti=1;i<=idx;i++)cnt[i]=0;//用memset清空数组会爆炸哦}return0;}

三、马拉车(M a n a c h e r \pmb{Manacher}Manacher)

模板:P3805
M a n a c h e r ManacherManacher算法用于解决最长回文串问题。
首先,我们向字符串开头结尾及每个字符之间加入‘#’,将回文串长度统一为奇数。
暴力方法:枚举中间项和长度,向两边拓展,最终回文串长度为l e n / 2 len/2len/2,时间复杂度O ( n 2 ) O(n^2)O(n2)
以以下字符串为例(省略了‘#’):
a b c e f e c b x b c e f e c b x a\ b\ c\ e\ f\ e\ c\ b\ x\ b\ c\ e\ f\ e\ c\ b\ xabcefecbxbcefecbx
M a n a c h e r ManacherManacher算法中,需要维护以下变量:
1.m a x r maxrmaxr:表示[ 1 , i − 1 ] [1,i-1][1,i1]个字符内可拓展到的最长回文串右边界(如i = 12 i=12i=12m a x r = 15 maxr=15maxr=15);
2.m i d midmid:表示当前最长回文串的中间项下标(如i = 12 i=12i=12m i d = 8 mid=8mid=8);
3.p [ i ] p[i]p[i]:表示第i ii个字符可向外拓展的最长长度。
显然,需要更新p [ i ] p[i]p[i]的值,考虑两种情况:
1 ◯ \textcircled 11p [ i ] > = m a x r p[i]>=maxrp[i]>=maxr:直接暴力向外拓展即可;
2 ◯ \textcircled 22p [ i ] < m a x r p[i]<maxrp[i]<maxr:依旧以i = 12 i=12i=12为例,对此,f ff一定能找到关于m i d midmid对称的另一个f ff,下标为m i d × 2 − i mid \times 2-imid×2i,即4。
p [ 4 ] p[4]p[4]显然是计算好的,所以可以利用对称性推出p [ 12 ] p[12]p[12]
考虑到p [ 4 ] p[4]p[4]向左拓展,对应p [ 12 ] p[12]p[12]会向右拓展。
如果p [ 4 ] p[4]p[4]不大于m a x r − i + 1 maxr-i+1maxri+1,则一定可以拓展到。(因为回文串内是对称的)
反之,则一定不能拓展到,因为不保证m a x r maxrmaxr右边字符仍对称,此时p [ i ] p[i]p[i]的最大值为m a x r − i + 1 maxr-i+1maxri+1

代码

#include<bits/stdc++.h>usingnamespacestd;#defineN11000005intp[2*N];//记得乘2string s="#",s1;intmain(){cin>>s1;for(charc:s1){s.push_back(c);s.push_back('#');//不能用加法,因为加法是O(n)的}intmaxr=0,mid=0,ans=0;for(inti=0;i<s.size();i++){if(i<=maxr)p[i]=min(p[mid*2-i],maxr-i+1);elsep[i]=1;while(i>=p[i]&&i+p[i]<s.size()&&s[i+p[i]]==s[i-p[i]])p[i]++;//暴力拓展if(i+p[i]-1>maxr){maxr=i+p[i]-1;mid=i;}//更新ans=max(ans,p[i]*2-1);}cout<<ans/2;//最终答案return0;}

继续战斗!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 4:06:44

一块砖,四只手——合金日记灶台篇(下)

Bold 钩子&#xff1a; 收与放——不是设计&#xff0c;是被辨认出来的。025 老罗手心朝里收旗&#xff0c;030 老石手心朝外嵌名。两篇隔了五十三年&#xff0c;两个动作&#xff0c;同一种「顿」。三句三分钟&#xff1a;1.五个字到一千三百字——「修城墙的人」怎么从四个字…

作者头像 李华
网站建设 2026/7/17 4:05:05

HarmonyOS鸿蒙PC平台nodejs三方库移植实战(bcrypt和 sqlite3移植笔记)

本文记录下移植nodejs三方库bcrypt和 sqlite3到鸿蒙PC上的踩坑过程和经验分享。鸿蒙PC平台nodejs三方库移植也很简单。鸿蒙 PC 安装 bcrypt 和sqlite3三方库实录&#xff1a;预编译与源码编译双路实战&#xff0c;关于 HarmonyOS Node.js 原生模块的兼容性测试验证总结笔记。 …

作者头像 李华
网站建设 2026/7/17 4:04:22

【Python基础】Python开发环境搭建实战操作详解

目录 一、前言 二、Python 基本介绍 2.1 Python 核心特点 2.2 Python 应用领域 2.3 Python 优缺点 2.4 现代 Python 生态趋势 2.5 Python 使用建议 三、Python 环境搭建 3.1 获取安装包 3.2 安装过程 3.3 效果验证 四、Python 编程初体验 4.1 Hello World 输出 4.…

作者头像 李华
网站建设 2026/7/17 4:03:47

VScode:使用TeamoRouter的API服务

TeamoRouter的优势 TeamoRouter是一个包含多种大语言模型的中转平台&#xff0c;可以间接调用 Claude、GPT、Gemini 、Deepseek等各种 AI 模型&#xff0c;同时提供API服务。 1.价格便宜 如图所示&#xff0c;无需多言。 2.操作省心 无需翻墙&#xff0c;担心网络环境是否…

作者头像 李华
网站建设 2026/7/17 4:03:32

C语言实现健壮字符串替换函数:从内存管理到工程实践

1. 项目概述与核心价值最近在整理一个老项目的代码&#xff0c;里面充斥着各种手写的、风格各异的字符串替换逻辑&#xff0c;看得人头大。有的用strtok加循环硬拼&#xff0c;有的自己写指针挪来挪去&#xff0c;稍不注意就缓冲区溢出或者内存泄漏。这让我下定决心&#xff0c…

作者头像 李华
网站建设 2026/7/17 4:03:23

Windows 11 23H2新特性与ARM64架构解析

1. Windows 11 23H2版本概述Windows 11 23H2是微软在2023年下半年推出的重大功能更新版本&#xff0c;作为Windows 11系统的第二个年度更新&#xff0c;它带来了多项性能改进和新功能增强。这个版本特别值得关注的是它对ARM64架构设备的原生支持&#xff0c;使得采用高通骁龙等…

作者头像 李华