Manacher(馬拉車) O n 回文子串

2021-09-25 09:27:23 字數 2830 閱讀 1989

manacher

一、背景

2023年,manacher發明了manacher演算法(中文名:馬拉車演算法),是乙個可以在o(n)的複雜度中返回字串s中最長回文子串長度的演算法,十分巧妙。

讓我們舉個栗子,栗子:

1.字串:abbababa        最長回文子串:5(abbababa

2.字串:abcbbabbc      最長回文子串:7(abcbbabbc

3.字串:abccbaba        最長回文子串:6(abccbaba)

傳統方法是,遍歷每個字元,以該字元為中心向兩邊查詢。時間複雜度為o(n^2),效率很差;

而這個神奇的manacher演算法將複雜度提公升到了o(n)。

來一起瞅一瞅它是如何工作的吧。

二、演算法過程分析

回文分為奇回文(ababa)和偶回文(abba),這裡比較難以處理,我們使用乙個(sao)(cao)(zuo)(很重要)。我們將字串首尾和每個字元間插入乙個字元(注意:這個自符在串中並未出現)例如:'#'.

栗子!栗子!

這樣原串中的偶回文(abba)與奇回文(adcacda),變成了(#a#d#d#a#)與(#a#d#c#a#c#d#a#)兩個奇回文

定義陣列p,用p[i]表示以i為中心的最長回文半徑。栗子在這裡:

那,p[i]該如何求呢?

p[i]-1正好就是原字元中的最長回文串長度了。

讓我們一起找到正解。

請看下圖:

定義兩個變數mx和id。mx就是以id為中心的最長回文右邊界,也就是mx=id+p[id],隨後我們需要mx做出它的最大貢獻。

假設我們在求p[i](以i為中心的最長回文半徑),如果i

if(i

p[i]=min(p[2*id-i],mx-i);

2*id-i是i關於id的對稱點(上圖j)(證明:i-id=id-j),而p[j]表示以j為中心的最長回文半徑,這樣我們就可以利用p[j]和mx加快速度了。

為什麼要用p[j]和mx-i取min來更新,什麼鬼?

淡定,淡定。我們想一下,p[j](以j為中心的最長回文半徑)是已經知道了(因為是從前面掃過來的),若是p[j]>mx-i,我們是可以知道以j為中心,以mx的對稱點到j的距離為半徑形成的回文字串是肯定存在的,並且id的左邊直到mx的對稱點與id的右邊 直到mx是一一對應的,不難理解mx是i目前可以更新到的最大回文半徑;若p[j]取完min就是最大的回文半徑嗎?

顯然不是,接下來的暴力往後掃就好了(學oi的都有暴力傾向)。

三、**

#include#include

#include

#include

using

namespace

std;

char s[11000002];

char s_new[21000002];//

存新增字元後的字串

int p[21000002];

int init()

s_new[j]='

\0';//

處理邊界,防止越界(容易忘記)

return j;//

返回s_new的長度

}int manacher()

max_len=max(max_len,p[i]-1

); }

return

max_len; }

intmain()

四、複雜度

完結撒花(複雜度不會證明呀,因為我是蒟蒻)

最長回文長度 manacher(馬拉車)

給出乙個只由小寫英文本元a,b,c y,z組成的字串s,求s中最長回文串的長度.回文就是正反讀都是一樣的字串,如aba,abba等 input 輸入有多組case,不超過120組,每組輸入為一行小寫英文本元a,b,c y,z組成的字串s 兩組case之間由空行隔開 該空行不用處理 字串長度len 1...

Manacher(馬拉車) O n 回文子串

manacher 一 背景 1975年,manacher發明了manacher演算法 中文名 馬拉車演算法 是乙個可以在o n 的複雜度中返回字串s中最長回文子串長度的演算法,十分巧妙。讓我們舉個栗子,栗子 1.字串 abbababa 最長回文子串 5 abbababa 2.字串 abcbbabbc...

Manacher 馬拉車演算法

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