算法學習-最長迴文子串

題目

給定字符串str,若子串s是迴文串,稱s爲str的迴文字串。設計算法,計算str的最長迴文字串。

枚舉所有字串,顯然是一種解法,但效率太過低下。


算法解析

  • 因爲迴文串有奇數和偶數的不同,判斷一個串是否是迴文串,往往要分開編寫,造成代碼拖沓。
  • 一個簡單的事實:纏度爲n的字符串,共有n-1個“鄰接”,加上首字符的前面,和末字符的後面,共n+1的“空”。因此,字符串本身和“空”一起,共有2n+1個,必定是奇數。如abbc-〉#a#b#c#;aba-〉#a#b#a#
  • 因此,將帶計算母串擴展成gap串,計算迴文字串的過程中,只考慮奇數匹配即可。
  • 字符串12212321-〉s[]="$#1#2#2#1#2#3#2#1#";爲了處理統一,最前面加一位未出現的字符,如$
  • 用一個數組P[i]來記錄以字符S[i]爲中心的最長迴文字串向左/右擴張的長度(包括S[i]),比如S和P的對應關係:
  • S  # 1 # 2 # 2 # 1 # 2 # 3 # 2 # 1 #
  • P  1 2 1 2 5 2 1 4 1 2 1 6 1 2 1 2 1
    • P[i]-1正好是原字符串中迴文串的總長度

下面介紹一下回文算法的核心算法思想Manacher算法

如下圖


  • 這裏需要求的是i的迴文字串的個數,mx爲目前匹配的最遠的位置,爲0到i-1中k+P[k]最大的數,代碼裏有體現,現在已知的是i以前的所有迴文字串是求出來的。
  • 記i關於id的對稱點位j(=2*id-i),若此時滿足條件mx-i〉P[j];則有如下:
    • 記my爲mx關於id的對稱點(my=2*id-mx);
    • 由於以S[id]爲中心的最大回文子串爲S[my+1...id...mx-1],即:S[my+1,...,id]與S[id,...,mx-1]對稱,而i和j關於id對稱,因此P[i]=P[j](P[j]是已知的)。

  • 記關於id的對稱點爲j(=2*id-i),若此時滿足條件mx-i〈P[j],則有如下:
    • 記my爲mx關於id的對稱點(my=2*id-mx);
    • 由於以S[id]爲中心的最大回文子串爲S[my+1...id...mx-1],即:S[my+1,...,id]與S[id,...,mx-1]對稱,而i和j關於id對稱,因此P[i]至少等於mx-i(途中綠色框部分)。

代碼如下所示

void Manacher(char* s, int* P)
{
	int size = strlen(s);
	P[0] = 1;
	int id = 0;
	int mx = 1;
	for (int i = 1; i < size; i++)
	{
		if (mx > i)//mx比i大,說明i被mx控制住了
		{
			P[i] = P[2*id - i] ? P[2*id - i] < (mx - i);
		}
		else
		{
			P[i] = 1;
		}
		for (; s[i + P[i]] == s[i - P[i]]; P[i]++);
		if (mx < i + P[i])
		{
			mx = i + P[i];
			id = i;
		}
	}
}





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