HDU3068 回文串 Manacher演算法

2021-09-07 08:29:43 字數 1655 閱讀 3366

好久沒有刷題了,雖然參加過acm,但是始終沒有融會貫通,沒有學個徹底。我幹啥都是半吊子,一瓶子不滿半瓶子晃蕩。

就連簡單的manacher演算法我也沒有刷過,常常為歲月蹉跎而感到後悔。

給定乙個字串s,求最長回文子串。

回文子串的回文指的是abccba這種從前往後讀和從後往前讀一樣。

子串必須連續(比如從i到j,s[i:j]),不是最長子序列(最長回文子串行怎麼求?),子串行是可以不連續的。

ans[i]表示以字元i為中心的最長回文子串的長度

now表示now+ans[now]取得最大值的那個下標

對於當前字元i,如果i處在以now為中心的回文子串裡,那麼ans[i]的求法可以參考i關於now的對稱點的回文子串長度,也就是ans[now-(i-now)].

例如:1j34now67i9,假設ans[j]=1,那麼ans[i]也等於1,因為i和j都處在以now為中心的回文子串裡面,它們是對稱的。

上面所述即為演算法關鍵,其餘情形很容易自己想到。

但是manacher演算法用到了兩個技巧

ans[i]中記錄的是以i為中心的最長回文子串,如果不作處理,這樣只能夠檢測出長度為奇數的回文子串的最大長度。所以有乙個巧妙的預處理。

給定字串abcc,擴充成#a#b#c#c#。

#a#b#a# 長度為3,以字元為中心的情況

#a#a#a#a# 長度為4,以#為中心的情況

這樣奇數偶數統一化處理。

如果在for迴圈中檢測兩個條件,那是很費事的,效率低。

如何判斷乙個條件有很多次無效的判斷?就看這個條件發揮作用,影響程式分支的次數和進行條件求值的次數。

邊界條件判斷影響分支的次數很少,但卻每次都要進行判斷。

通過加上乙個終止字元,就能夠避免邊界條件判斷。

在manacher演算法中,要求回文子串同時要防止下標越界。所以直接在開頭插入乙個$字元,這樣肯定因為失配而終止。

manacher演算法為線性複雜度,因為從前往後有乙個指標一直是單方向運動,沒有回溯。

對於陣列中的多個指標,如果都是單向運動,儘管它們運動的順序和步長不同,那也一定是線性複雜度。

#include#includeusing namespace std;

const int n = 110009;

char s[n];

char a[n * 2];

int ans[n * 2];

int now;

int main()

a[j++] = '#';

//開始演算法主體部分

now = 1;

ans[0] = ans[1] = 0;

for (int i = 2; i < j; i++)

else

else}}

//尋找答案,這部分可以直接放在求ans的過程中

int ma = 0;

for (int i = 1; i < j; i++)

printf("%d\n", ma);

}return 0;

}

動態規劃:複雜度都是o(n^2)

方法一:

a[i,j]表示s[i,j]之間最長回文子串行。則a[i,j]可以來自a[i+1,j-1],a[i-1,j],a[i,j-1].

方法二:

將s和s反過來得到的字串求最長公共子串行

hdu3068回文串Manacher演算法

題目就是求乙個串的最大回文子串的字元個數。manacher 演算法先貼乙個模板。好短啊。話說此題字尾陣列可能會超時的。發現這個模板有點問題,在此更正一下。更正後 include includeusing namespace std const int n 300010 int n,p n char ...

HDU 3068 最長回文串

用的manacher法,o n 複雜度,證明跟kmp演算法一樣說不清 基本上是參考部落格鏈結 dp法記憶體不夠,中心擴充套件法時間不夠 manacher法 include include include include include include include include include ...

HDU 3068 最長回文串

解法1 根據是奇數串還是偶數串,遍歷中點,更新最長max值 複雜度o n 2 解法2 manacher 馬拉車演算法 o n 馬拉車演算法 1.中間插入 符號,統一變為奇數串規避奇偶問題 2.使用乙個輔助p陣列,p i 表示以 i 為中心的最長回文的半徑,p i 1正好是原字串中最長回文串的長度 3...