Manacher演算法求解最長迴文串
阿新 • • 發佈:2020-07-28
推薦的參考博文
根據博主的介紹,我寫出了下面的C++程式碼
#include<bits/stdc++.h> using namespace std; string Pre(string s) {//將s轉化成ManacherString int lenth = s.size(); string line="#"; for(int i=0;i<lenth;i++) { line+=s[i]; line+="#"; } return line; } string Manacher(string aim) { aim = Pre(aim);//字串預處理 int lenth = aim.size(); int* temp = new int[lenth]; for(int i=0;i<lenth;i++)temp[i]=1;//初始化迴文半徑陣列 //下面是核心程式碼 int p=0,C=-1,R=-1;//p當前訪問字元,C最右迴文邊界的對稱中心,R最右迴文邊界 while(p<lenth) { if(p>R)//要移動的位置p在R的右側 { int s = p; while(s<lenth&&2*p-s>=0&&aim[s]==aim[2*p-s])s++;//以p為中心向兩側擴張 C=p;R=s-1;temp[p]=s-p; } else// if(p<=R) 第二種情形:要移動的位置p不在R的右側 { int p2 = 2*C-p;//p2是p1以C為對稱中心的對稱點 int cL = 2*C-R;//cL是以C為對稱中心的迴文子串的左邊界 int pL = p2-temp[p2]+1;//pL是以p2為對稱中心的迴文子串的左邊界 //第二情形的三種情況 if(cL==pL) { int s = R; while(2*p-s>=0&&s<lenth&&aim[s]==aim[2*p-s])s++; C=p;R=s-1;temp[p]=s-p; } else temp[p] = (cL<pL)? temp[p2]:(R-p+1); } p++;//千萬不要忘了這個 }//while //下面查詢答案 int maxnum = -1; int maxp=-1; string ans="";//用於儲存將要返回的最長迴文串 //下面檢測最長迴文串的中心 for(int i=0;i<lenth;i++) { if(temp[i]>maxnum) { maxnum = temp[i]; maxp = i; } } for(int i=maxp-maxnum+1;i<maxp+maxnum;i++) {//整理最長迴文串 if(aim[i]!='#')ans+=aim[i]; } delete[] temp;//刪除長度記錄陣列 return ans; } int main() { string aim = "acbbcbds"; cout<<Manacher(aim)<<endl; return 0; }//輸出的是cbbc
先不要急著抄寫,下面我們對核心程式碼進行壓縮並使其模板化
string Pre(string s) {//將s轉化成ManacherString int lenth = s.size(); string line="#"; for(int i=0;i<lenth;i++) { line+=s[i]; line+="#"; } return line; } int NormalExtend(int center,int lenth,string& aim,int& C,int& R) {//對稱中心center,字串長度lenth,字串引用aim,最右迴文邊界的對稱中心C,最右迴文邊界R int s = max(center,R); while(s<lenth && 2*center-s>=0 && aim[s]==aim[2*center-s]) s++; C=center; R=s-1; return s-center;//該值會被賦給標記陣列temp[center] } string Manacher(string aim) { aim = Pre(aim);//字串預處理 int lenth = aim.size(); int* temp = new int[lenth]; for(int i=0;i<lenth;i++)temp[i]=1;//初始化迴文半徑陣列 //下面是核心程式碼的壓縮版本 int p=0,C=-1,R=-1;//p當前訪問字元,C最右迴文邊界的對稱中心,R最右迴文邊界 while(p<lenth) { int p2 = 2*C-p;//p2是p1以C為對稱中心的對稱點 int cL = 2*C-R;//cL是以C為對稱中心的迴文子串的左邊界 int pL = p2-temp[p2]+1;//pL是以p2為對稱中心的迴文子串的左邊界 if(p>R || (p<=R&&cL==pL)) temp[p] = NormalExtend(p,lenth,aim,C,R); else temp[p] = (cL<pL)? temp[p2]:(R-p+1); p++; } //下面查詢答案 int maxnum = -1; int maxp=-1; string ans="";//用於儲存將要返回的最長迴文串 //下面檢測最長迴文串的中心 for(int i=0;i<lenth;i++) { if(temp[i]>maxnum) { maxnum = temp[i]; maxp = i; } } for(int i=maxp-maxnum+1;i<maxp+maxnum;i++) {//整理最長迴文串 if(aim[i]!='#')ans+=aim[i]; } delete[] temp;//刪除長度記錄陣列 return ans; }
OK