Manacher 回文数算法

Manacher算法

(统计一个字符串中最大可组成的回文数)

1:原理

​ 形如 abba,abcba 的字符串中,采用暴力匹配法,遍历每个元素,对该元素作为中心元素,向两侧延申比较(但该做法只适用于奇数串,偶数串无法满足)

1:初始化 :由于 奇+偶 = 偶+奇 = 奇数,可以通过添加无关元素法将串变成奇数串。

​ abba : #a#b#b#a#, abcba : #a#b#c#b#a# -->都转换为奇数串

char s[maxn],s1[maxn*2+10];
int p[maxn*2+10];                    //注意p是s1串的回文项

int init(){
	int j = 0;
	for(int i=0;i<n;i++){
		s1[j++] = '#';
		s1[j++] = s[i];
	}
	s1[j++] = '#';
	return j;
}
2:匹配过程的分类讨论:
	###### 首先:c :回文中心   		r:回文右端点
c 为已经确定的回文中心,L->c == R->c,遍历 i
(1)当且仅当 i <r 并且 i’ 的回文半径不超过L 时,有 p[i] == p[i’],而 i’ 实际 = C*2-i;

img

(2) 当且仅当 i<r 并且 i‘ 的回文半径超过 L时, p[i] = R-i;
###### 		证明:当 p[ i' ] > i'-L时,x == y, 又由C的回文半径得 y == k,但是由于C的回文半径最大是到R,所以      x != z,因此 :z != k ,p[i]的回文半径只能到R,证毕。

img

(3)当且仅当 i<r 并且p[i’]的半径刚好到L:p[i]的半径有可能超出R,需按暴力法继续匹配:

img

(4)当 i>=r 的时候,即不在已知回文范围内,p[i] = 1;
3:关于maxn-1的理解:

​ maxn 确实是p[i]中的最大值,但是 s1[i] 是 s[i] 长度的两倍多,当匹配回文串相等的时候,会发现回文半径最左端与最右端一定 是 ‘#‘,所以减一是正解。

2:源代码

void Manacher(){
	int n = init();
	int c = -1,r = -1,maxn = -1;
	for(int i=0;i<n;i++){
		if(i>=r)
			p[i] = 1;
		else 
			p[i] = min(p[c*2-i], r-i);				//情况 1,2
			
		while(p[i]+i < n && i-p[i]>=0){				//情况 3
			if(s1[p[i]+i] == s1[i-p[i]])
				p[i]++;
			else break;
		}
		
		if(p[i]+i > r){							//更新 
			r = p[i]+i;
			c = i;
		}
		maxn = max(maxn, p[i]);
	} 
	maxn = maxn-1;								//重点,最后一定要减一
	cout<<maxn<<endl;
}
3:经典例题

hdu 3068

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值