最長迴文串的解法---Manacher算法

最長迴文串的求解,顧名思義,給函數一個字符創str,在該字符串中找到最長的迴文,例如:


str=“abababc”,其中單個字母a,b,c都可以看做迴文,其長度爲1;aba,bab也是迴文,長度爲3;ababa,babab,也是迴文,其長度爲5。我們可以發現在一個字符串中有許多不同長度的迴文,而我們的任務就是找到最長的迴文的長度值,即5。


      最直接的方法就是以每個字符爲中心向左右兩邊,同時擴展尋找以該字符爲中心的最長迴文。事實上,manacher算法的核心思想也是基於此操作的,不一樣的是該方法使用了動態規劃的思想,從左往右一次求解以字符爲中心的最長迴文,每次的求解都是建立在該字符往左的已知結論上。具體的原理可以參考鏈接處,

http://blog.csdn.net/xingyeyongheng/article/details/9310555


注意,Manacher方法的時間複雜度是O(n),n是字符串中的字符總數。


針對hiho上的最長迴文問題的代碼如下

<span style="font-size:14px;">#include<stdio.h>
#include<string.h>
#include<algorithm>

using namespace std;

const int N_MAX=2000040;
int rad[N_MAX];
char str[N_MAX];
int len;

int Solve()
{
	//fill(rad,rad+N_MAX,0);
	scanf("%s",str);
	len=strlen(str);

	if(len==0)
		return 0;

	for(int i=2*len+1;i>1;i-=2){     //對源字符串變形,將“ababc”變爲“$#a#b#a#b#c#”,後續計算過程中從左數第一“#”開始計算rad,下標i從1開始
		str[i]='#';
		str[i-1]=str[i/2-1];
	}
	str[0]='$';str[1]='#';str[2*len+2]='\0';

	/*for(int i=0;i<strlen(str);i++)
		printf("%c",str[i]);
	printf("\n");*/

	int id(0),mx(0),mxrd(0);    //Manacher算法
	for(int i=1;i<=2*len+1;i++){
		rad[i]=mx>i?min(rad[2*id-i],mx-i):1;         //在最大邊界外,rad[i]初始值爲1,否則取i關於id對稱處的rad,或者id的最大右邊界mx減i
		while(str[i+rad[i]]==str[i-rad[i]])rad[i]++;
		if(rad[i]+i>mx){
			id=i;
			mx=i+rad[i];
		}
		if(mxrd<rad[i])
			mxrd=rad[i];
		//printf("%d",rad[i]);
	}
	return mxrd-1;                                       //rad[i]-1剛好等於對應的迴文子字符串的長度,i可能對應一個字母,也可能對應#

}

int main()
{
	int num;
	scanf("%d",&num);
	fflush(stdin);
	while(num--){
		printf("%d\n",Solve());
	}
	
	
	return 0;
}</span>

      做了一道Leetcode上的longest Palindrome substring的題,明白了改變原字符串爲加‘#’形式的重要性,即下面的注意事項:

       一定要在首位各加一個作爲開始和結尾的標誌,並且必須不同,例如開頭是‘$’,那麼結尾可以用‘\0’。總之,不能一樣。因爲你在尋找回文,如果一樣了,那麼我們豈不是暗中加長了迴文的可能性。

發佈了45 篇原創文章 · 獲贊 15 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章