Manacher 马拉车板子

Manacher算法是一种通过O(n)的时间复杂的算出字符串最长回文串的一种算法
在这里插入图片描述
因为回文串可能是奇数也可能是偶数,不好判断,为了保证字符串回文串总是一个奇数,先对字符串进行预处理,每隔一个字符,插入一个特殊的字符,保证其总是一个奇数
用p[i]表示字符串中以i为中心的最长回文串半径
对于奇数回文串
在这里插入图片描述
偶数回文串同理
可以发现max(p[i]-1)就是我们要的最大回文串长度

那么如何计算p[i]呢?
令mx为上一次操作的最长回文子串的最右端的下一位,mid为mx对应回文串的中心点。
如果i大于等于mx,先让p[i]=1,然后以i为中心开始遍历其最长的回文串,并对p[i]做出改变,操作完成后,更新新的mx和mid
如果i小于mx,说明该字符已经包含在某字符串里,根据回文串的对称关系
p[i]=p[2*mid-i],但由于以2*mid-i为中心的回文串可能会大于原回文串长度
所以p[i]=min(mx-i,p[2*mid-i])
这样可以从mx开始继续统计新的回文串长度,从而实现mx新的更新

int manacher()
{
	int sum=0,k=1;
	//构建新的奇数总串 
	s[k++]='#';
	for(int i=0;i<a.size();i++)
	{
		s[k++]='#';
		s[k++]=a[i];
	}
	s[k]='#';
	//开始计算最长长度
	int mx=0,mid;
	for(int i=1;i<=k;i++)
	{
		if(i<mx)
		p[i]=min(mx-i,p[2*mid-i]);
		else
		p[i]=1;
		while(s[i-p[i]]==s[i+p[i]])
		p[i]++;
		if(i+p[i]>mx)
		{
			mx=i+p[i];mid=i;sum=max(sum,p[i]);
		}
	}
	return sum-1;
}
### 实现与解释马拉算法 #### 一、算法概述 马拉算法Manacher's Algorithm)用于在线性时间内查找字符串中的最长回文子串。该算法通过巧妙地处理奇偶长度的回文问题,使得整个过程可以在 O(n) 时间复杂度下完成[^1]。 #### 二、算法过程分析 ##### 1. 字符串预处理 为了统一处理不同长度的回文情况,通常会在原字符串之间插入特殊字符 `#` ,并添加头尾两个不同的保护字符 `$` 和 `@` 。这样做的目的是让所有的回文中心都有一个明确的位置,并且不会越界访问[^2]。 例如:"abba" 被转换成 "$#a#b#b#a#@" ##### 2. 原字符串与新字符串的关联 经过上述变换后的字符串称为辅助串 S' , 对应位置 i 处的最大半径 P[i] 表示以第i个字符为中心能扩展出去最远距离的一半加一 (即实际回文长度除以2再加1)[^3]。 ##### 3. 利用已知信息加速计算 在遍历过程中维护三个变量:当前最大右端点 id, 当前最大右侧边界 mr 及其对应的中心 pos;当遇到新的待求解点 j 时分两种情况进行讨论: ###### 3.1 维护数据 如果j位于mr之内,则尝试借用pos处的信息来减少不必要的比较次数;否则直接从零开始匹配直到无法继续为止。 ###### 3.2 初始化规则 根据 j 是否处于已有记录的有效区间内采取不同策略初始化 p[j]: - **若 j 属于有效区域** :设 k=2*pos-j 即关于pos对称的那个索引位上的值作为初始估计值 min(p[k], mr-j+1), 这样既考虑到了镜像关系又防止超出范围; - **反之则置为默认最小值1**, 因为我们至少知道它自己本身构成的一个单字符回文. ###### 3.3 探测阶段 无论哪种情形都需要进一步验证是否存在更长的可能性,具体做法是从p[j]-1往两侧逐次试探直至不满足条件停止更新p[j][^3]。 最后每当发现更大的mr就及时刷新id和pos以便后续节点能够受益于此优化措施. ```python def manacher(s): # Preprocess the string to handle even-length palindromes uniformly. t = '#'.join(f'^{s}$') n = len(t) p = [0]*n center = right = 0 max_len = 0 index = 0 for i in range(1,n-1): mirror = 2 * center - i if right > i: p[i] = min(right-i,p[mirror]) while t[i+(1+p[i])] == t[i-(1+p[i])]: p[i]+=1 if i + p[i]>right: center=i right=center+p[i] if p[i]>max_len: max_len=p[i] index=i start=(index-max_len)//2 return s[start:start+max_len] ``` 此代码实现了完整的马拉算法逻辑,包括必要的预处理步骤以及核心循环结构,最终返回输入字符串中最长连续回文子序列的内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值