LeetCode 5 最長迴文子串 Manacher線性算法

題目鏈接:https://oj.leetcode.com/problems/longest-palindromic-substring/


迴文串即正向反向序列都一樣的連續序列 如abba,abcba...

爲了統一回文串的偶數情況和奇數情況,可以向串中插入不相關的字符,例如abba->#a#b#b#a#, abcba->#a#b#c#b#a#


建立數組arr[]記錄主串中以第i個字符爲中心的迴文串向右延伸的長度(即向右覆蓋長度,不包括s[i])

例如:

第一種情況:


設變量mx爲當前向右最大覆蓋位置下標,id爲該回文串對稱中心下標。在例子中,達到最右覆蓋位置的爲index=5,覆蓋到5+arr[5]=8.所以,此時,mx=8,id=5

在計算arr[7]時(圖中‘?’處i=7),可以利用arr[0~6]的值,發現7位於以id爲對稱中心的覆蓋範圍內(圖中黃色部分)。並且,i=7的對稱位置id*2-i=3的覆蓋範圍(藍色部分)並未超出id的覆蓋範圍(黃色部分),所以,arr[7]可直接利用arr[3]的值,令arr[7]=arr[3].


另外一種情況:i未超出黃色部分,但藍色不服超出了黃色部分。如下圖:

此時,arr[7]的值至少爲其關於id=5的對稱位置:arr[3].所以,先爲arr[7]賦初值=arr[3].然後,再從(i+arr[i]+1),(i-arr[i]-1)分別向兩端遍歷即可。


最後一種情況,即i超出了黃色部分(i>=mx),這時,只能爲arr[i]賦初值arr[i]=0,並向兩端遍歷


代碼:

class Solution
{
public:
	string longestPalindrome(string s)
	{
		string tem;
		for(int i=0;i<s.length();i++)
		{
			tem.push_back('#');
			tem.push_back(s[i]);
		}
		tem.push_back('#');
		s=tem;
		tem.clear();

		int *arr=new int[s.length()+5];		//以i爲中心最長串向右延伸長度
		memset(arr,0,sizeof(arr));
		int id=0;							//對稱中心
		int mx=0;							//右邊界
		int maxid=0;						//最長迴文中心
		for(int i=1;i<s.length();i++)
		{
			if(i>=mx)						//在範圍外
				arr[i]=0;
			else							//在範圍內
			{
				if(arr[id*2-i]<arr[id]+id-i)
				{
					arr[i]=arr[id*2-i];
					continue;
				}
				else
					arr[i]=mx-i;			//肯定>or=該值
			}
			while(s[i-arr[i]-1]==s[i+arr[i]+1]&&i-arr[i]-1>=0&&i+arr[i]+1<s.length())
				arr[i]++;

			if(i+arr[i]>mx)					//更新延伸最右位置
			{
				id=i;
				mx=id+arr[id];
			}
			if(arr[i]>arr[maxid])				//更新最長串中心
				maxid=i;

		}
		for(int i=maxid-arr[maxid];i<=maxid+arr[maxid];i++)
		{
			if(s[i]=='#')
				continue;
			else
				tem.push_back(s[i]);
		}	
		return tem;

	}

};


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