求最大回文子串(manacher算法)

原文出處:http://www.cnblogs.com/grandyang/p/4475985.html

manache算法俗稱馬拉車算法,該算法的作用是求一個字符串中的最大回文子串,例如"11123321"。

馬拉車算法找回文串的方法是從中間往左右兩邊找,但是這樣找就會遇到幾個問題;第一個,比如"1221",馬拉車算法就不好找(所以會用到預處理);第二個這樣暴力找的時間開銷大,所以會用一個p數組來記錄一下包括了當前能夠形成迴文串的最大回文半徑(迴文串字符數量的一半,這裏的一半肯定整數,不會出現小數,原因請看預處理),來快速跳轉找當前迴文串的一個可能大小(因爲後面可能會增大,但一定不會減小),舉個栗子,如下圖:

因爲一個以id爲中心的迴文串中的兩邊個對稱的迴文串(一個以2*id-1爲中心的迴文串,另一個以i爲中心的迴文串是相等的)所以:

當2*mx-i<=p[2*id-i]時,

1

當2*mx-i>p[2*id-i]時,2

  1. 預處理

將輸入的字符在每一個字符的兩邊加上一個"#"(其他符號也行,必須與輸入的字符不一樣),在一個字符前面加個"*"(其他符號也行,不能和輸入字符或者"#"一樣),例如:

"11123321"     ->    "*#1#1#1#2#3#3#2#1#"

加"#"的原因:可以將每一個原字符子串變成一個奇數個數的子串,保證每個子串是一字符爲中心的串,如果不是以一個字符爲中心的串,在求一個迴文串時只能去一個字符一個字符擴展後再去判斷。

加"*":提供非迴文(結束迴文擴展操作,防止溢出,出現s[-1]的情況)。

 

題目地址:https://ac.nowcoder.com/acm/contest/549/B

code:

/*
	馬拉車算法manacher 
*/

#include<bits/stdc++.h>

using namespace std;

const int mn=10005;

int p[mn*2],id,mx;
string s;

void manache(string t){
	int i,j;
	s.clear();
	s+="*#";
	for(i=0;i<2*t.size();i++){
		s+=t[i%t.size()];
		s+="#";
	}
//	cout<<s<<endl;
	int maxl=0;
	memset(p,0,sizeof p);
	for(i=0;i<s.size();++i){
		p[i]=mx>i?min(p[2*id-i],mx-i):1;
		while(s[i-p[i]]==s[i+p[i]]&&(p[i]-1<s.size()/4)) ++p[i];
		if(mx<p[i]+i){
			mx=i+p[i];
			id=i;
		}
//		cout<<p[i]<<' '<<i<<endl;
		maxl=max(maxl,p[i]);
	}
	cout<<maxl-1<<endl;
}

int main(){
	string t;
	while(cin>>t){
		manache(t);
	}
	
	return 0;
}

如果還是看不懂的話,請看原文博客,圖片畫的灰常具體!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章