manacher演算法 O n 求最長回文子串

2021-07-05 12:17:25 字數 1354 閱讀 3629

樸素的做法是求出以每個字元為中心的回文串長度,複雜度為

而manacher演算法可以在o(n)時間內求解,奇數長度和偶數長度可以統一處理。根據回文串的對稱性,避免了大量不必要的比較。

處理技巧:

①相鄰的字元之間插入乙個分隔符,串的首尾也要加,以「#」為例,則長度為n的字串經過處理之後變成2n+1奇數長度的字串。為防止向兩邊擴充套件時越界,可以在首尾處加兩個不匹配的特殊字元,末尾為"\0"無需處理,首部加乙個"$"符號。

②用乙個陣列p記錄以每個字元為中心的最長回文串半徑,並記錄當前已掃瞄過的字元邊界bound。對任意位置

i) i + p[j] <= bound,如下圖所示,j的回文串在x的回文串內部,則根據對稱性,i處左右p[j]長度的串必定相等,所以i向右p[j]都無需再檢查,從p[j]以後開始檢查

ii) i + p[j] > bound,如下圖所示,j的回文串越過了x的回文串邊界,由於以x為中心的最長回文串最多隻到bound處,所以bound以後的部位未知,只能跳過bound - i長度的檢查。

下面說明p[i]與最長回文串長度的關係。

①中心i為字元時,說明原回文串的長度為奇數(#…#a#…#),則回文串長度為p[i] - 2 + 1= p[i] - 1; (只看右邊那一半,除了最後乙個"#",每個"#"可以當成其後面字元的映象,再加上中心字元,一共p[i] - 2 + 1)

②中心i為'#'時,說明原回文串長度為偶數(#…a#a…#),則回文串長度為p[i] - 1;(只看右邊那一半,每個字元前面的"#"都可以用其映象來代替,最後多出來乙個"#")

例題:**如下:

#include #include using namespace std;

#define n 110005

#define min(a, b) (a) < (b) ? (a) : (b)

char s[n], a[n << 1];

int p[n << 1];

int main()

int n = j, bound = 0, cur, ans = 0; //cur表示當前最遠邊界的回文串中心,即圖中的x

for(int i = 1; i < n; ++i)

if(p[i] > ans)

ans = p[i];

}printf("%d\n", ans - 1);

getchar();

}return 0;

}

求最長回文串 Manacher演算法

o n 效率的字串求最長回文串,感覺這個blog上寫的很詳細 有幾個要點 1 先要將字串擴充套件成2 l 1長度的,在每兩個字元之間要加上乙個用不到的字元,比如 方便處理偶數回文串。2 在擴充套件後的字串兩端要加一些特殊字元,防越界。3 ra i 陣列表示以i為中點的最長回文串,mx表示以j 1 j...

manacher演算法求最長回文串長度

manacher演算法 定義陣列p i 表示以i為中心的 包含i這個字元 回文串半徑長 將字串s從前掃到後for int i 0 i由於s是從前掃到後的,所以需要計算p i 時一定已經計算好了p 1 p i 1 假設現在掃瞄到了i k這個位置,現在需要計算p i k 定義maxlen是i k位置前所...

求最長回文子串 Manacher 演算法

給定乙個字串,求出其最長回文子串。例如 1 s abcd 最長回文長度為 1 2 s ababa 最長回文長度為 5 3 s abccb 最長回文長度為 4,即 bccb。以上問題的傳統思路大概是,遍歷每乙個字元,以該字元為中點向兩邊查詢。其時間複雜度為 o n2 很不高效。1975 年,乙個叫 m...