马拉车算法

马拉车算法是用于找出一个字符串中的最长回文串。

通过使用马拉车算法可以在O(n)的时间内,列出从字符串头部开始所有的回文,主要利用的是回文字符串左右镜像对称的特征。

比如对于字符串 abbbabbbb 扩展之后变成了$#a#b#b#b#a#b#b#b#b#

扩展的意义是把不论是奇数还是偶数的字符串全部都变成奇数进行处理(不包括$)。

我们从左往右依次进行计算,然后使用id表示当前搜索到的最长回文串的中心点位置,使用mx表示该回文串的半径。 

 

这个时候i因为小于mx,所以可以利用当前id的左右镜像的对称性。

i对称点j的计算 j=id-(i-id)=2id-i

其中p[i]表示以sNew[i]为中心的最长回文子串的半径,若p[i]=1,则该回文子串就是sNew[i]本身。

p[j]=p[2*10-14]=p[6]=5;//这个时候mx-i=17-14=3<5 说明当前最大回文串的对称性只能管到mx之后的对称性就得一一重新匹配了。

如果mx-i>p[j] 这是i点的回文特性就和j的全完一样了,因为id的回文的对称性把它给包括了。

如果mx<i,说明当前点没法利用之前最长回文串的对称特征了只能一个一个匹配。

string Manacher(string s)
{

	string sNew = "$#";
    //在最左边使用$符号,匹配的时候就肯定不会有对称的出现所以可以防止地址越界
	for (auto iter = s.cbegin(); iter != s.cend(); iter++)
	{
		sNew += *iter;
		sNew += "#";
	}

	int iNewSize = sNew.size();
	int iMaxSubStringLength = -1;    // 最长回文子串的长度
	int iMaxSubStringPos = -1;       // 最长回文子串中心点的位置
	vector<int> p(iNewSize, 0);
	int id = 0;
	int mx = 0;

	for (int i = 1; i < iNewSize; i++)
	{
		if (i < mx)
		{
			p[i] = min(p[2 * id - i], mx - i);
		}
		else
		{
			p[i] = 1;
		}

		while (sNew[i - p[i]] == sNew[i + p[i]])  
		{
			p[i]++;
		}

		if (mx < i + p[i])  //找出当前最长的回文串 
		{
			id = i;
			mx = i + p[i];
		}
		if (p[i] - 1 > iMaxSubStringLength)
		{
			iMaxSubStringLength = p[i] - 1;
			iMaxSubStringPos = i;
		}
	}

	auto iStart = s.cbegin() + (iMaxSubStringPos - iMaxSubStringLength - 1) / 2; 
    // 将最长回文子串起始位置转换回原串
	return string(iStart, iStart + iMaxSubStringLength);
}

代码出处:https://blog.csdn.net/the_star_is_at/article/details/53354958  谢谢

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值