首页 > 编程语言 > 详细

【模板】manacher算法

时间:2020-10-24 09:58:14      阅读:34      评论:0      收藏:0      [点我收藏+]

看进阶指南的时候看到的算法,正好最近没啥事干来学一下

大致题意

给一个长度为\(n\)字符串\(S\),求\(S\)中的最长回文字串

\(n≤1.1×10^7\)


分析

算法一

暴力

枚举每个点能扩散到的最大长度

时间复杂度\(O(n^2)\)


算法二

\(hash+\)二分

建立出\(S\)的前后缀\(hash\)值,然后二分答案,找到最大扩展长度

时间复杂度\(O(nlogn)\)


算法三

\(manacher\)麻辣串算法

算法流程

1.在每两个字符间插入一个额外字符,以去掉偶回文串的情况


2.定义\(r_i\)表示以\(i\)为中心时的最大回文半径

\(R\)表示当前情况能扩展到的最右字符\((即最右回文右端点)\)

\(mid\)表示最右回文的中心

考虑每个新进来的字符的情况:

\(1.\) \(i∈[mid,R]\)

显然,\(i\)有一个关于\(mid\)的对称点\(j = mid×2-i\)

根据对称性,\(j\)周围的字符和\(i\)周围的字符一定相同,于是可以先用\(r_j\)去更新\(r_i\)

\(r_i = min(r_{mid×2-i},r_{mid}-i+mid)\)

(右侧不能大于\(R\),否则处于未知的位置,无法保证正确性)

最后再去试试\(i\)还能不能扩展,同时更新\(R\)\(mid\)的值

\(2.\) \(i∈(R,n]\)

此时\(i\)处于一个未知的位置,因此只能暴力扩展,同时更新\(R\)\(mid\)的值

最后的答案即为\((2*max(r_i)-2)/2 = max(r_i)-1\)

由于\(R\)最多会向右移\(n\)次,因此总时间复杂度为线性(\(O(n)\))

\(code\)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 91000000;
char c[MAXN];
char s[MAXN];
int L[MAXN],R[MAXN]; 
int MAX_R;
int r[MAXN],len,mid; 
void manacher(){
	for(int i=1;i<len;i++){
		if(MAX_R>i&&mid<=i) r[i] = min(r[mid*2-i],r[mid]-i+mid);
		else r[i] = 1;
		while(s[i+r[i]]==s[i-r[i]]) r[i]++;
		if(i+r[i]>MAX_R){
			mid = i;
			MAX_R = r[i]+i;	
		}
	}
}
int main(){
	cin>>c;
	s[0] =‘#‘,s[1] = ‘#‘;
	len = strlen(c); 
	for(int i=0;i<len;i++){
		s[i*2+2] = c[i];
		s[i*2+3] = ‘#‘;
	} 
	len = len*2+2;
	int ans = -114514;
	manacher();
	for(int i=0;i<len;i++){
		ans = max(ans,r[i]);
	}
	cout<<ans-1;
} 

【模板】manacher算法

原文:https://www.cnblogs.com/xcxc82/p/13866825.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!