看了好久的Manacher算法,覺得還是要自己畫一遍,自己把代碼寫一遍才能理解
下面分享一下,如果有錯,希望指正
簡陋版本的,但是他基本只是做到了求取最長回文字符串,嚴格來說它并不是Manacher’s Algorithm-馬拉車算法
#include<stdio.h> 、char qdu[100050];
int manachar()
{int i;int res = 0;for (i = 1; qdu[i]; i++){int l = i;int r = i;while (qdu[i] == qdu[r + 1])r++;i = r;while (qdu[l - 1] == qdu[r + 1]) {r++;l--;}if (res < r - l + 1)res = r - l + 1;}return res;
}
int main()
{int loop;qdu[0] = '$';gets(qdu + 1);printf("%d\n", manachar());return 0;
}
Manacher’s Algorithm-馬拉車算法 時間復雜度O(n)
互聯網偵察微信公眾號講解,雖然文章很長,但是他講解的十分清楚
這篇博文簡單的介紹了思路
下面是核心代碼,我們先看圖
//Manacher算法計算過程
int MANACHER(char *st, int len)
{int mx = 0, ans = 0, po = 0;//mx即為當前計算回文串最右邊字符的最大值for (int i = 1; i <= len; i++){if (mx > i)Len[i] = min(mx - i, Len[2 * po - i]);//在Len[j]和mx-i中取個小elseLen[i] = 1;//如果i>=mx,要從頭開始匹配while (st[i - Len[i]] == st[i + Len[i]])Len[i]++;if (Len[i] + i > mx)//若新計算的回文串右端點位置大于mx,要更新po和mx的值{mx = Len[i] + i;po = i;}ans = max(ans, Len[i]);}return ans - 1;//返回Len[i]中的最大值-1即為原串的最長回文子串額長度
}
首先對字符串進行預處理,處理原因是防止偶數問題(可看前面的博文)
處理后的結果進行Manacher算法。
第一個@是0,其余默認從1開始計數
首先看3 的左右都是#號所以1+1 = 2;
到了1,它可以數到6,碰到了@就不相等了,而他的回文字符串長度也是6
等到了1右邊的#號,我們就可以根據對稱特點,求出他和1左邊的#號是同一個值(前提是這個沒有超過有邊界,黃色橫線所示)
到這里基本就結束了
這里給出完整代碼,可以自己跑一編,看看效果
#define maxn 1000010
#include <cstdio>
#include <iostream>
#include <algorithm>using namespace std;char str[maxn] = {"3212343219"};//原字符串
char tmp[maxn << 1];//轉換后的字符串
int Len[maxn << 1];//轉換原始串
int INIT(char *st)
{int i, len = strlen(st);tmp[0] = '@';//字符串開頭增加一個特殊字符,防止越界for (i = 1; i <= 2 * len; i += 2){tmp[i] = '#';tmp[i + 1] = st[i / 2];}tmp[2 * len + 1] = '#';tmp[2 * len + 2] = '$';//字符串結尾加一個字符,防止越界tmp[2 * len + 3] = 0;return 2 * len + 1;//返回轉換字符串的長度
}
//Manacher算法計算過程
int MANACHER(char *st, int len)
{int mx = 0, ans = 0, po = 0;//mx即為當前計算回文串最右邊字符的最大值for (int i = 1; i <= len; i++){if (mx > i)Len[i] = min(mx - i, Len[2 * po - i]);//在Len[j]和mx-i中取個小elseLen[i] = 1;//如果i>=mx,要從頭開始匹配while (st[i - Len[i]] == st[i + Len[i]])Len[i]++;if (Len[i] + i > mx)//若新計算的回文串右端點位置大于mx,要更新po和mx的值{mx = Len[i] + i;po = i;}ans = max(ans, Len[i]);}return ans - 1;//返回Len[i]中的最大值-1即為原串的最長回文子串額長度
}int main()
{int len = INIT(str);MANACHER(tmp, len);
}