Manacher 最长回文子串

本文深入解析Manacher算法,一种高效求解最长回文子串问题的方法。通过在原字符串中插入特殊字符,算法能够同时处理奇数和偶数长度的回文串,利用已知回文半径加速后续字符的回文串半径计算,极大提升了查找效率。
用途
  • 求最长回文串, 过程中更新max(Maxlen,RL[i]−1)max(Maxlen,RL[i]-1)max(MaxlenRL[i]1)
  • 求回文串的数量,∑i=0lenRL[i]2\sum_{i=0}^{len}\frac{RL[i]}{2}i=0len2RL[i]

RL[i]RL[i]RL[i] :关于i的回文半径
MaxRightMaxRightMaxRight:pos能到达的最右端的位置
MaxLenMaxLenMaxLen:记录答案

  • 首先在原字符串中插入字符“#”
    例如:“abba” -> "#a#b#b#a#"这样不影响回文串,好处是可以同时解决长度为奇偶的字符串,而且(回文半径 - 1)就是原来的回文串长度
  • 问题转化为如何高效的求每个字符的回文串半径,当我们知道pos能到达的最右端位置MaxRightMaxRightMaxRight,我们继续向后枚举字符串求它的回文半径,我们关心的是i这个位置是在MaxRight的左边还是右边, 在左边分为两种情况,右边一种情况。
  • 求出来最小值之后再向两边扩展得到最长的回文半径, 然后更新posposposMaxRightMaxRightMaxRight

在这里插入图片描述

int RL[maxn << 1];
int Manacher(string s) {
	string t;
	for (int i = 0; i < (int)s.size(); ++i) {
   		t += s[i];
   		t += '#';
   	}
   	s = "#" + t;
   	int MaxRight = 0, pos = 0, MaxLen = 0;
   	for (int i = 0; i < (int)s.size(); ++i) {
   		if (i < MaxRight)	RL[i] = min(RL[2 * pos - i], MaxRight - i + 1); // 好多这里写的是 MaxRight - i,个人感觉根据算法思想应该+1计算长度。
   		else 	RL[i] = 1;
   		int l = i - RL[i];
   		int r = i + RL[i];
   		while (l >= 0 && r < (int)s.size() && s[l] == s[r])	{
   			RL[i] += 1;
   			l = i - RL[i];
   			r = i + RL[i];
   		}
   		if (RL[i] + i - 1 > MaxRight) {
   			MaxRight = RL[i] + i - 1;
   			pos = i;
   		}
   		MaxLen = max(MaxLen, RL[i]);
   	}
   	return MaxLen - 1;
}
int RL[maxn << 1];
char s[maxn], t[maxn << 1];
int Manacher(char *s) {
	if (s[strlen(s) - 1] == '\n')	s[strlen(s) - 1] = '\0';
	int lens = strlen(s), len = 0;
	t[len++] = '#';
	for (int i = 0; i < lens; ++i) {
   		t[len++] = s[i];
   		t[len++] = '#';
   	}
   	int MaxRight = 0, pos = 0, MaxLen = 0;
   	for (int i = 0; i < len; ++i) {
   		if (i < MaxRight)	RL[i] = min(RL[2 * pos - i], MaxRight - i + 1); // 好多这里写的是 MaxRight - i,个人感觉根据算法思想应该+1计算长度。
   		else 	RL[i] = 1;
   		int l = i - RL[i];
   		int r = i + RL[i];
   		while (l >= 0 && r < len && t[l] == t[r])	{
   			RL[i] += 1;
   			l = i - RL[i];
   			r = i + RL[i];
   		}
   		if (RL[i] + i - 1 > MaxRight) {
   			MaxRight = RL[i] + i - 1;
   			pos = i;
   		}
   		MaxLen = max(MaxLen, RL[i]);
   	}
   	return MaxLen - 1;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值