這個演算法是用來求乙個字串中的最長回文串的長度的,且時間複雜度是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...