判斷最長迴文串——暴力、延展、Manacher

1. 暴力

時間複雜度O(n^3)。

2. 延展

 以某一字符爲中心,設置left, right兩個變量同時向外擴,判斷他們指向字符是否相同。注意分奇偶討論。時間複雜度O(n^2)。

3. Manacher 馬拉車

 代碼註釋:

 1 const int MAXN = 110009;
 2 char ma[MAXN * 2];   //因爲要添加'#',所以長度要開兩倍
 3 int mp[MAXN * 2];
 4 char s[MAXN];
 5 
 6 void Manacher(char s[], int len) {
 7     
 8     // 1. 構造字符串,添加'#',使長度變爲奇數(2 * len - 1)
 9     int l = 0;
10     ma[l++] = '$';   // 設置邊界
11     ma[l++] = '#';
12     for(int i = 0; i < len; i ++) {
13         ma[l++] = s[i];
14         ma[l++] = '#';
15     }
16     ma[l] = 0;
17     
18     // 核心: 求迴文半徑, 迴文半徑包括中心點
19     int mx = 0; // mx代表可達的最右值
20     int id = 0; // id代表mx的中心  
21     for(int i = 0; i < l; i ++) {
22         mp[i] = mx > i ? min(mp[2 * id - i], mx - i) : 1;
23         while(ma[i + mp[i]] == ma[i - mp[i]]) {
24             mp[i] ++;
25         }
26         if(i + mp[i] > mx) {
27             mx = i + mp[i];
28             id = i;
29         }
30     }
31 
32 }
33 
34 int main()
35 {
36 
37     while(scanf("%s", s) != EOF) {
38         int len = strlen(s);
39         Manacher(s, len);
40         int ans = 0;
41         for(int i = 0; i < 2 * len + 2; i ++) {   // 尋找最長的迴文半徑,即迴文串長度
42             ans = max(ans, mp[i] - 1);  // 迴文半徑減1就是原迴文串的長度(迴文半徑中虛加了#)
43             cout << mp[i] << " ";
44         }
45         printf("%d\n", ans);
46     }
47 
48     return 0;
49 }

時間複雜度O(n)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章