Mancher 最长回文字串

本文介绍了Manacher算法解决最长回文子串问题,对比了暴力求解的缺陷与修正版,并详细解析了Manacher算法的优化过程和代码实现。
摘要由CSDN通过智能技术生成

Mancher 最长回文字串


暴力方法 O(n^2)

1.缺陷版本

遍历每个字符
以每个字符为中间位置向左右两边扩一位。
不能发现偶数回文
baoli1

2.改正版本

先再字符串每个字符之间插入 #
再逐个向两边阔
就不会错过偶数回文 得到的值 /2 就是每个位置(包括虚轴)的回文长度
baoli2

插入的字符不一定必须是# ,可以是任何字符,和原串内容的相同字符也可以


Mancher o(n)

mancher是以暴力的改正版本为基础,在暴力得到Arr[i]的时候做优化

在遍历过程中记录每一次扩的最右边界
i<R内的时候,就能优化,否则继续暴力。
优化就是通过轴C找到 i'的回文半径 判断三种情况

  1. i’的范围在区间内 [i] = [i'] 直接优化
  2. i’的范围在区间外 回文半径至少是R-i
  3. i’的范围压线 回文半径至少是R-i || i'的回文半径

之后再while()

模板

// t为处理过的字符串,p为记录长度的数组
memset(p, 0, sizeof(p));
// mx为已判断回文串最右边位置,id为中间位置,mmax记录p数组中最大值
int mx = 0, id = 0, mmax = 0;
for (int i = 1; t[i]; i++) {
	p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
	while (t[i + p[i]] == t[i - p[i]])
		p[i]++;
	if (i + p[i] > mx) {
		mx = i + p[i];
		id = i;
	}
	maxx = max(maxx,p[i]);
}
return mmax - 1;

code

#include <bits/stdc++.h>
using namespace std;

//string str = "#1#2#2#1#";
string getstrr(string s){  // s --> str
	string str; 
	int len = s.length();
	for(int i=0;i<len;i++){
		str.push_back('#');
		str.push_back(s[i]);
	}
	str.push_back('#');
	return str;
}
int getmaxlen(string s){
	
	string str = getstrr(s.c_str());
	int parr[str.length()];
	int C = -1;
	int R = -1;  //记录遍历过的回文最右的下一位
	int maxx = -1;
	for(int i=0;i<str.length();i++){
		//i位置扩的区域 最小是多大  i'       i的右半部分 
		parr[i] = R > i ? min(parr[2*C-i] , R-i):1;
		
		while(i+parr[i] < str.length() && i-parr[i] > -1){
			if(str[i+parr[i]]==str[i-parr[i]]){
				parr[i]++;
			}else{
				break;
			}
		} 
		if(i+ parr[i] > R){
			R = i + parr[i]; 
			C = i;
		}
		maxx = max(maxx,parr[i]);
	}
	return maxx-1; //最长回文长度 
}
int main()
{
	string s = "1221"; 
	cout<<getmaxlen(s.c_str())<<endl; 
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值