2025年河南省暑期青少年程序设计能力提升集训DAY2线性字符串算法(哈希+KMP+Manacher+最小表示法)

·字符串哈希

那很暴力了

关于哈希的介绍这里复制粘贴了:

Hash是一种数据结构,叫做Hash表(哈希表),也叫散列表。关于Hash的实现,其实与
散化 颇为类似。就是把若⼲的复杂的信息映射 到一个比较容易维护的值域去。具体的实现
方式是散列函数,即Hash函数,其原理是对于一个数据,选取一个关键键值 ,那么这个数
据在Hash表中的位置就是 f(k)。那么这个对应关系f()就是哈希函数
即:hash[i]=hash[i-1]*p+f(i)  (p为大质数,常用13331,mod取更大即可,我用无符号long long不考虑mod)
个人理解就是一段p进制的数,如果用哈希就能直接比较这一段与另一段的关系
这里说一下求子串哈希值的通项公式
哈希值为hash[i]-hash[j-1]\times p^{i-j+1}
或者是\left (\left ( hash[i]-hash[j-1]\times p^{i-j+1} \right)\mod mod+mod \right )\mod mod(用无符号long long的话不用这个也行)

·KMP算法

时间复杂度 O(nm) -> O(n+m)

学过了就简单说一下吧,本质上就是求前后缀,目的是更快的往后遍历(右移更快一些并且不用跳回来再次遍历)

首先是比较难的pmt前后缀数组,这里给一下模板代码

模板

void PMT(string s){
	ll j=0,n=s.size();
	af(i,1,n-1){
		while(j&&s[i]!=s[j]) j=pmt[j-1];
		if(s[i]==s[j]) j++;
		pmt[i]=j;
	}
}
然后是标准KMP模板
void KMP(string s1,string s2){
	ll j=0;
	af(i,0,s1.size()-1){
		while(j&&s1[i]!=s2[j]) j=pmt[j-1];
		if(s1[i]==s2[j]) j++;
		if(j==s2.size()){
			j=pmt[j-1];
		}
	}
}

·Manacher算法

时间复杂度 O(n^2) -> O(n)

Manacher算法的核心思想是利用回文串的对称性质,通过维护一个"当前最远回文右边界"和对应的中心点,来避免重复计算。

主要步骤:

  1. 预处理:在原字符串的每个字符间插入一个特殊字符(如'#'),将奇数和偶数长度的回文统一处理为奇数长度。

  2. 维护变量

    • P[i]:记录以i为中心的最长回文半径

    • C:当前回文中心

    • R:当前回文右边界

  3. 算法流程

    遍历字符串,对于每个位置i:
    • 如果i在R内,镜像解决,可以利用对称性快速获取P[i]的初始值

    • 暴力更新向两边扩展以确定P[i]的准确值

    • 如果i+P[i]超过R,继续暴力更新,更新C和R

这里解释足够详细,考的题也不多,不做赘述了

·最小表示法

也就是找字符串的最小表示(好像说了跟没说一样)

最小表示法是一种用于找到字符串或序列的“最小表示”的算法。它主要用于处理循环同构的字符串,找到其中字典序最小的那个。例如,字符串 bcda 的表示有 bcda, cdabdabcabcd,其中 abcd是字典序最小的表示。

通过双指针ij来确定字符串的字典序

给一下模板

模板

n=read();
	af(i,0,n-1) a[i]=read();
	ll i=0,j=1,k=0;
	while(i<=n&&j<=n&&k<=n){
		if(a[(i+k)%n]>a[(j+k)%n]) i=i+k+1,k=0;
		if(a[(i+k)%n]<a[(j+k)%n]) j=j+k+1,k=0;
		if(a[(i+k)%n]==a[(j+k)%n]) k++; if(i==j) i++;
	}
	ll ans=min(i,j); 
	af(p,0,n-1) cout<<a[(p+ans)%n]<<' ';

比较过程:

情况1:s[i+k] == s[j+k]
         k++
情况2:s[i+k] > s[j+k]
         i = i + k + 1
情况3:s[i+k] < s[j+k]
        j = j + k + 1
终止条件:i 或 j 超出字符串长度


题目的话回来再说吧(绝对不是我没写完)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值