馬拉車演算法是一種計算最長回文子串的演算法,以其優秀的線性複雜度聞名於世,相較於\(o(n^2)\)的\(dp\)演算法和會被特殊資料卡到\(o(n^2)\)的暴力演算法,馬拉車演算法無疑是求解最長回文子串的最優選擇。
最長回文子串分為偶數串和奇數串,為了避免這些問題,馬拉車演算法將每個字元與字元間插入乙個特殊字元,在兩頭插入不同的字元,以免越界。
馬拉車演算法定義:\(r\)為當前已知的對稱的最右邊的點,\(mid\)為\(r\)的對稱軸,\(f_i\)為以\(i\)為對稱軸的最長回文子串的回文半徑
則我們遇到乙個\(i\),分兩種情況討論
若\(mid \leq i \leq r\),則\(f_i\)可能為他的對稱點,即\(f_\),但如果\(i+f_\)大於了\(r\),則就不能保證它的正確性,而能保證正確性的區域在哪兒呢?只有\(r\)以內,所以要和\(r-i+1\)取乙個\(min\),然而我們不能保證它的最長回文子串一定是這個範圍,所以我們要暴力拓展一下,直到不能拓展為止。
若\(r,那麼暴力拓展即可。
而做完這一切後,看看\(r\)和\(mid\)有沒有要更新的。
而我們統計答案時一定要減掉插入的字元,我們發現,統計出來的回文半徑一定是乙個奇數,則結尾是乙個\(\#\),將對面的對過來,得到答案為\(f_i-1\)最終答案即為\(min(f_i)-1\)
那麼馬拉車演算法的時間複雜度是怎麼證明為線性呢?
若是\(mid \leq i \leq r\)且取值為\(f_\),那麼是一定不會拓展的,因為這還在這個回文半徑裡面,兩邊肯定是相同的
而其他兩種情況,\(r\)是一定隨著動的。所以複雜度為線性,即\(o(n)\)
**實現:
#include#include#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
int n,m,k,f[2000039],mr,mid,ans;
char s[2000039],x;
int main()
printf("%d\n",ans);
}
馬拉車演算法
思路筆記 上述情況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 題意在給定的字串中找...