演算法學習 manacher

2022-07-24 12:03:11 字數 1528 閱讀 1421

【沒有前置知識】

【解決的問題】

大多數都和回文串有關

例如:字串中長度最長的回文串

【演算法學習】

(請牢記這個目的)

先來講樸素演算法:

從1~n,對每個字元都從其自身開始,向兩邊遞推,如果左右兩邊字元相同,範圍+1,長度+2

這樣的複雜度是n^2的

而 manacher 的優化方式和 kmp 有所類似,都是利用之前已經匹配過和得到過的資訊,簡化當前的運算

回文串有兩種,一種是奇數長度一種是偶數長度,顯然他們是需要被區別對待的

但是在理解了manacher的本質之後,我們只需要做微小改動就能夠同時解決這兩個問題 

首先引入 l 和 r ,代表當前已經找到的回文串中,右端點最右的回文串的左右端點,初始為 0 和 1

設陣列d為我們所需要求取的陣列,即每個字元所對應的以其自身為中心的最長回文串長度

假設我們現在要求d [ i ] 的值,而 d [ i ] 之前的值已經求出來了

當我們現在所求的i < r時,即現在這個字元是在乙個回文串中的時候

我們就可以利用這個資訊,來處理他

求在(l,r)這個回文串中和他位置對稱的 d [ j ]

因為在回文串中,所以 d [ i ] 和 d[ j ] 兩邊一定長度內的字元是相同的

而這個一定長度就是,以 s [ j ] 為中心的回文串的長度,可能超過了(l,r)的範圍

所以不能看作回文串,只有在這個範圍內才能看作回文串

所以我們能夠借用這個因素得到的 d [ i ] 兩邊的回文串長度就是min( d [ j ] , j + 1 - r )

得到這個長度之後,我們為了得到最終答案,還需要繼續擴充套件 以 s [ i ] 為中心的回文串

所以用樸素演算法繼續擴充套件

在擴充套件過程中,如果以 s [ i ] 為中心的回文串的最右邊端點超過了 r 

我們就需要更新  l , r ,保證他們所代表的意義不變

然後我們在來討論之前沒有談論的兩種回文串的問題

常見的方法是在每兩個字元間都插入乙個不可能出現的字元,這樣就能夠將所有的奇偶字元轉化統一

也還有另外一種方法

通過訪問雙倍長度,列舉每一種情況

實際上和插入字元類似,只不過是把字元插入這種操作

通過數字下標的形式取代

建議畫圖理解

【複雜度】

實際上我們可以看出來,至始至終每次都是 r 在不斷的右移,並沒有出現重複,所以最後的複雜度和字串的長度等同

1

void manacher(char *s,int n,int *d)

217 }

void manacher(char *s,int n,int *d)

}

view code

Manacher演算法 學習總結

求乙個序列的最大回文子串,我們需要需要用到manacher演算法。其作用在於能夠在o n 的時間內求出最長回文子串,同時也能夠求出回文子串的個數。且時間效率高,十分簡潔。我們知道,回文子串分為奇數回文子串和偶數回文子串。由於兩種情況的處理較為麻煩,我們可以考慮在期間插入字元在簡化問題。例如例子 ab...

Manacher演算法 學習筆記

首先,強烈安利一篇文章,這篇文章對於 manacher 的講解本人感覺非常到位。傳送門相信大家都知道的乙個方法 列舉字串的每乙個位置作為回文子串的對稱中心,同時向左向右擴充套件,判斷是否相等,然後每次儲存之前求取的最大回文子串長度,時間複雜度為 o n 2 在列舉時,還需要考慮對奇數回文串和偶數回文...

Manacher演算法學習筆記

manacher演算法是乙個求乙個字串中最長回文連續子串行的演算法 p3805 模板 manacher 演算法 description 求最長回文子串的長度 solution 我們先引入乙個 o n 2 的做法,列舉每個字元為回文串的中心,嘗試向兩邊擴充套件,用擴充套件的最大長度更新答案。為了下文描...