學習manacher(最長公共回文串演算法)

2022-03-13 13:48:51 字數 2321 閱讀 2894

給定乙個字串求出其中最長個公共回文串.

舉列子: abab   -->回文串長度為2

以前的演算法諸如: 擴充套件kmp求法過於麻煩,看到有一篇博文(寫了乙個關於這樣的演算法,按耐不住自己內心的小激動,就去學了下,於是將自己學習的一點點的理解記錄下來:

它的處理方法是:  對於這樣乙個字串: abab;

a b a b     我們對於每乙個字串的進行逐個匹配

1 2 2 1

對於奇數長度的字串  ababa   -->回文串的長度為:

a b a b a   ( 這是對於每乙個字串進行模式匹配)  之間複雜度為 o(n*m)

1 2 3  2 1

而現在我們學習的一種演算法是時間複雜度為o(n)

演算法的思想是: 設定乙個匹配半徑ra , 然後分為三種情況進行討論: (當然討論主要是縮減不必要的重複匹配)

由於已經有好些博主寫的較為詳細,自己就不在胡亂填鴨了.....

以下引用的是 這位樓主的部落格  (

首先,在字串s中,用rad[i]表示第i個字元的回文半徑,即rad[i]盡可能大,且滿足:

s[i-rad[i],i-1]=s[i+1,i+rad[i]]

很明顯,求出了所有的rad,就求出了所有的長度為奇數的回文子串.

至於偶數的怎麼求,最後再講.

假設現在求出了rad[1..i-1],現在要求後面的rad值,並且通過前面的操作,得知了當前字元i的rad值至少為j.現在通過試圖擴大j來掃瞄,

求出了rad[i].再假設現在有個指標k,從1迴圈到rad[i],試圖通過某些手段來求出[i+1,i+rad[i]]的rad值.

根據定義,黑色的部分是乙個回文子串,兩段紅色的區間全等.

因為之前已經求出了rad[i-k],所以直接用它.有3種情況:

如圖,rad[i-k]的範圍為青色.因為黑色的部分是回文的,且青色的部分在黑色的部分裡面,根據定義,很容易得出:rad[i+k]=rad[i-k].為了方便下文,這裡的rad[i+k]=rad[i-k]=min(rad[i]-k,rad[i-k]).

根據上面兩種情況,可以得出結論:當rad[i]-k!=rad[i-k]的時候,rad[i+k]=min(rad[i]-k,rad[i-k]).

注意:當rad[i]-k==rad[i-k]的時候,就不同了,這是第三種情況:

如圖,通過和第一種情況對比之後會發現,因為青色的部分沒有超出黑色的部分,所以即使橙色的部分全等,也無法像第一種情況一樣引出矛盾,因此橙色的部分是

有可能全等的,但是,根據已知的資訊,我們不知道橙色的部分是多長,因此就把i指標移到i+k的位置,j=rad[i-k](因為它的rad值至少為

rad[i-k]),等下次迴圈的時候再做了.

整個演算法就這樣.

至於時間複雜度為什麼是o(n),我已經證明了,但很難說清楚.所以自己體會吧.

上文還留有乙個問題,就是這樣只能算出奇數長度的回文子串,偶數的就不行.怎麼辦呢?有一種直接但比較笨的方法,就是做兩遍(因為兩個程式是差不多的,只

是rad值的意義和一些下標變了而已).但是寫兩個差不多的程式是很痛苦的,而且容易錯.所以一種比較好的方法就是在原來的串中每兩個字元之間加入乙個特

殊字元,再做.如:aabbaca,把它變成a#a#b#b#a#c#a,這樣的話,無論原來的回文子串長度是偶數還是奇數,現在都變成奇數了

於是有這種思想我們不難寫出這樣的**:

**:

1 #include2 #include

3 #include4

#define maxn 1000000

5char

str[maxn];

6int

ra[maxn];

7int min(int a,intb)8

11void init(char s,int

len)

19 s[en]='$'

;20}21

int manacher (int

len )

33if((i&1)&&ans

34 ans=ra[i];35}

36 memset(str,0,sizeof

(str));

37return

ans;38}

39int

main()

45return0;

46 }

view code

最長公共子串行 最長公共子串

1 最長公共子串行 採用動態規劃的思想,用乙個陣列dp i j 記錄a字串中i 1位置到b字串中j 1位置的最長公共子串行,若a i 1 b j 1 那麼dp i j dp i 1 j 1 1,若不相同,那麼dp i j 就是dp i 1 j 和dp i j 1 中的較大者。class lcs el...

最長公共子串行 最長公共子串

1.區別 找兩個字串的最長公共子串,這個子串要求在原字串中是連續的。而最長公共子串行則並不要求連續。2 最長公共子串 其實這是乙個序貫決策問題,可以用動態規劃來求解。我們採用乙個二維矩陣來記錄中間的結果。這個二維矩陣怎麼構造呢?直接舉個例子吧 bab 和 caba 當然我們現在一眼就可以看出來最長公...

最長公共子串 最長公共子串行

子串要求連續 子串行不要求連續 之前的做法是dp求子序列 include include include using namespace std const int inf 0x3f3f3f3f const int mod 1000000007 string s1,s2 int dp 1010 10...