Manacher 馬拉車 演算法詳解 證明和練習題

2021-10-13 02:59:58 字數 4288 閱讀 8489

這個演算法是用來求乙個字串中的最長回文串的長度的,且時間複雜度是o(n)。

1. 最長回文半徑長度陣列

2. 最右回文右邊界

3. 最右回文右邊界的最早到達點

對於乙個字串,它的每乙個位置i和最右回文右邊界之間的關係只可能有兩種情況:1. i不在最右回文右邊界裡;2. i在最右回文右邊界裡

為了方便,將最右回文右邊界即為r。

i在最右回文右邊界裡,此時又可細分為如下三種情況:

為了便於說明,將最右回文右邊界的最早到達點記為c,那麼c的最長回文子串的右邊界即為r,左邊界記為l。

c是最右回文右邊界的最早到達點,l與r是以c為中心的最長回文子串的左右邊界。對於i位置,由於它在r內,所以不必急著暴力擴張,先看看關於c的對稱點i』的回文區域是啥,那i』的回文區域怎麼得到呢?用之前求出的最長回文半徑長度陣列即可得到。上圖是i』的回文區域在[l, r]內的情況。此時i的回文區域和i』的相同,為啥呢?證明如下:

先證[r』, l』]為回文:設i』的回文區域是紅色範圍,左邊界為l,右邊界為r,r』是r關於c的對稱點,l』同理。由於[l, r]是回文,而[r』, l』]是[l, r]的對稱點,因此前者是後者的逆序,即[r』, l』]也為回文。

再證i的最大回文區域就是[r』, l』]:y是l的左邊一位元素,x是r右邊一位元素,x』與y』是x和y關於c的對稱點。當時計算i』的回文區域時,為啥沒把y和x考慮進去呢?肯定是他倆不相等啊,所以x』和y』也不相等,即i的最大回文區域就是[r』, l』]。

乙個例子:字串zkabatftabaky,c為f,那麼左右邊界為:z[kabatftabak]y,設i為倒數第四個位置(b),所以i關於c的對稱點i』在正數第4個位置(b),而i』的最長回文區域是[aba],在[l, r]裡(l在第乙個k位置,r在第二個k位置),所以i的回文區域即為[aba],那麼i的最長回文半徑長度陣列的值即為2(aba,半徑為ab/ba,故為2)。

此時i關於c的對稱點i』的最長回文串超過了c的最長回文串邊界l,那麼i的最長回文區域也不用算,半徑就是[i, r],證明如下:

做l關於i』的對稱點l』,r』同理。所以[l, l』]是回文,[r, r]也是回文,且[r, r]是[l, l』]的逆序。

由於c的最長回文區域是[l, r],並不是[x』, x],所以x』不等於x,否則最長回文區域就是[x』, x]了,而x』與y』關於i』對稱且在i』回文區域內,所以x』=y『,而y是y』關於c的對陣點,所以y『=y,綜上可以得出x不等於y,即這種情況下i的最長回文區域只能是[i, r]。

乙個例子,字串abcdcbatttabcdcf,c為第二個t,那麼其最長回文區域是:ab[cdcbatttabcdc]f,設i到了倒數第三個位置,那麼其對稱點i』在正數第四個位置,而i『的最長回文區域為abcdcba,超出了c的最長區域,因此i位置的最長回文為cdc,即回文半徑為2。

此時i的最長回文區域至少是[i, r],但能否更長還要看r後面的元素都是啥,也就是說這種情況下需要暴力擴張。

總結manacher演算法可以分為兩種大情況,分別是當前索引i在r內和不在r內,若不在r內,直接暴力擴張。

若在r內,根據i的對陣點i』最長回文區域的大小又可分為三種小情況:

**:

public

class

manacher

system.out.

println

(arrays.

tostring

(manacherstr));

return manacherstr;

}public

intmanacher

(string str)

char

chararr =

manacherstring

(str)

;int

parr =

newint

[chararr.length]

;int c =-1

;int r =-1

;int max = integer.min_value;

for(

int i =

0; i < chararr.length; i++

)else}if

(i + parr[i]

> r)

max = math.

max(max, parr[i]);

}return max;

}public

static

void

main

(string[

] args)

}

對上述**的說明:

關於這道題,可以用manacher演算法的思想來做。

首先找到以給出的字串最後乙個字元結尾的最長回文串,然後從頭開始,遇見最長回文串的開頭就停止,將這段字串逆序貼在整個字串的末尾就是答案,舉個例子:

只需對manacher演算法做一點改進: 有邊界第一次到字串末尾時就跳出,此時得到的即為以最後乙個字元結尾的最長回文串,注意,他不一定是所有回文串中最長的,但這沒關係,我們要的是以最後乙個字元結尾的最長回文串!!!。

public

class

manacher

system.out.

println

(arrays.

tostring

(manacherstr));

return manacherstr;

}public

intmanacher

(string str)

char

chararr =

manacherstring

(str)

;int

parr =

newint

[chararr.length]

;int c =-1

;int r =-1

;int max = integer.min_value;

int earlyc =-1

;for

(int i =

0; i < chararr.length; i++

)else}if

(i + parr[i]

> r)

if(r == chararr.length)

max = math.

max(max, parr[i]);

} system.out.

println

(earlyc)

;// 方式1

// char res = new char[str.length()-earlyc+1];

// for (int i = 0; i < res.length; i++)

// 方式2

char

res =

newchar[(

2*c-chararr.length+1)

/2];

int index =0;

for(

int i =

2*c-chararr.length; i >=

0; i--)}

system.out.

println

(string.

valueof

(res)

+" "

+ res.length)

;return max;

}public

static

void

main

(string[

] args)

}結果:

cba 3

Manacher 馬拉車演算法

給定乙個字串,求出其的最長回文子串 乙個將時間複雜度優化到o n 的演算法 暴力演算法,但不是純暴力,即按照做過的事情不再去做來優化 我們知道,乙個回文串要麼是奇數的串 aba 要麼是偶數的串 abba 可以看出,乙個回文串有乙個對稱軸 對於奇數串aba來說,對稱軸就是b 而對於偶數串abba來說,...

Manacher演算法(馬拉車)

演算法總結第三彈 manacher演算法,前面講了兩個字串相演算法 kmp和拓展kmp,這次來還是來總結乙個字串演算法,manacher演算法,我習慣叫他 馬拉車 演算法。相對於前面介紹的兩個演算法,manacher演算法的應用範圍要狹窄得多,但是它的思想和拓展kmp演算法有很多共通支出,所以在這裡...

馬拉車演算法manacher

1.預處理解決奇回文和偶回文問題 比如 str bcbaa 在每個字元的開頭,結尾和中間插入乙個特殊字元 來得到乙個新的字串 b c b a a 這樣對於原來字串中的奇回文 bcb 來說,在新的字串中變成了 b c b 還是奇回文,只是回文串長度從3變成了7 注意 中 i 1 0,與1按位與,如果i...