manacher』s algorithm,中文名叫馬拉車演算法,是一位名叫manacher的人在2023年提出的一種演算法,解決的問題是求最長回文子串,神奇之處在於將演算法的時間複雜度精進到了o(n),下面我們來詳細介紹下這個演算法的思路。
馬拉車演算法本質還是中心擴散,為了避免回文串是奇數還是偶數的情況,要對原始的回文串字元進行新增分隔符操作。
第一步:新增分隔符
假設分隔符為「#」,在字串「ababa」中新增後的結果是「#a#b#a#b#a#」。即新增後是結果字串的總數是奇數的。
第二步:計算輔助陣列
輔助陣列的作用就是記錄以每個字串為中心的回文串的資訊。
輔助陣列中的值,就是以當前的字元為中心,同時向兩邊進行擴散乙個位置,若兩邊相同,則繼續擴散,一直等到不相同為止,在當前字元的值中記錄下向兩邊擴散的位置大小。
例如圖中3下標的字元,以 char[3] = 『b』 為中心,同時向左邊向右擴散,走 1 步,左右兩邊都是 「#」,構成回文子串,繼續同時向左邊向右擴散,左邊是 「a」,右邊是 「b」,不匹配,最多能擴散的步數為 1 ,因此 p[3] = 1;
這種情況的輔助陣列會導致一種計算錯誤的結果。
馬拉車演算法詳解
那麼下面我們就來看如何求p陣列,需要新增兩個輔助變數 mx 和 id,其中 id 為能延伸到最右端的位置的那個回文子串的中心點位置,mx 是回文串能延伸到的最右端的位置,需要注意的是,這個 mx 位置的字元不屬於回文串,所以才能用 mx-i 來更新 p[i] 的長度而不用加1,由 mx 的更新方式 mx = i + p[i] 也能看出來 mx 是不在回文串範圍內的,這個演算法的最核心的一行如下:
p[i]
= mx > i ?
min(p[
2* id - i]
, mx - i):1
;
#include
#include
#include
using namespace std;
string manacher
(string s)
// process t
vector<
int>
p(t.
size()
,0);
int mx =
0, id =
0, reslen =
0, rescenter =0;
for(
int i =
1; i < t.
size()
;++i)
if(reslen < p[i])}
return s.
substr
((rescenter - reslen)/2
, reslen -1)
;}intmain()
馬拉車演算法
思路筆記 上述情況1和情況2又可以歸結為 i 的回文半徑 和 r i的距離 中小的那個就是i的回文半徑。include include includeusing namespace std string manacherstring string str return res int min int...
馬拉車演算法
馬拉車演算法是一種計算最長回文子串的演算法,以其優秀的線性複雜度聞名於世,相較於o n 2 o n 2 o n2 的dpdp dp演算法和會被特殊資料卡到o n 2 o n 2 o n2 的暴力演算法,馬拉車演算法無疑是求解最長回文子串的最優選擇。最長回文子串分為偶數串和奇數串,為了避免這些問題,馬...
馬拉車演算法
manacher char s maxn 1 int n,hw maxn 1 int l maxn 1 r maxn 1 void manacher char a n len 2 2 s n 0 int maxr 0,m 0 for int i 1 i n i manacher 題意在給定的字串中找...