manacher演算法及其應用
阿新 • • 發佈:2019-01-28
最近學習了牛客網的演算法初級班,學到了一些經典演算法
這裡整理一下manacher演算法,自己參考老師給的程式碼,轉成C++程式碼
#ifndef MANACHER_H #define MANACHER_H //Manacher演算法 :找出字串str中最長的迴文子串 #define MIN(a,b) a<b?a:b #define MAX(a,b) a>b?a:b #include<iostream> #include<vector> #include<string> using namespace std; //字串改造 //"123abx" //"#1#2#3#a#b#x#" string manacherString(string s) { string result = "#"; for (int i = 0; i != s.length(); ++i) result =result +s[i] + "#"; return result; } int manacher(string str) { if (str.length() < 1)//字串為空 return 0; string s = manacherString(str);//生成擴充套件字串 int R = -1;//最右迴文邊界的下標,不包括在迴文裡 int C = -1;//最右迴文半徑的中心,隨R變化。 int max = INT_MIN;//用來記錄最大回文半徑 vector<int>r(s.length(), 0);//記錄每個位置的最大回文半徑的陣列,長度為擴充套件陣列長度 for (int i = 0; i !=s.length(); ++i) { r[i] = R > i ? MIN(r[2 * C - i], R - i) : 1; //r[i]位置的最大回文半徑,最起碼的結果 while ((i + r[i])<s.length() &&( i - r[i])>=0)//再進一步看i處半徑能不能繼續擴,首先不越界 { if (s[i + r[i]] == s[i - r[i]])//還能擴 r[i]++; else//擴不了,while迴圈結束 break; } if (i + r[i] > R)//某一位置的最右迴文半徑,超過了邊界 { R = i + r[i];//更新邊界R C = i;//更新最右迴文半徑中心C,C伴隨著R變化,R更新,C也更新; } max = MAX(r[i], max); }//for迴圈結束; return max-1;//原字串的最大回文子串長度為擴充套件字串的最大回文半徑-1; } #endif
manacher演算法的擴充套件應用
//給定一個字串str1,只能往str1的後面新增字元變成str2,要求str2 //整體都是迴文串且最短。 //1、只要求出包含了str1中最後一個字元的最長迴文子串s即可。 //2、然後將子串s在str1中之前的字元逆序新增到str1末尾即可。 //如“abc12321”,包含“1”的最長迴文子串是“12321”, //將“abc”逆序新增到“abc12321”末尾,變成“abc12321cba”,即為所求的str2。 #ifndef MANACHER_SHORTEST_END_H #define MANACHER_SHORTEST_END_H #include<iostream> #include<vector> #include<string> #define MIN(a,b) a<b?a:b #define MAX(a,b) a>b?a:b using namespace std; //原字串變成擴充套件字串,長度為奇數 string manacherString(string s) { string result = "#"; for (int i = 0; i != s.length(); ++i) result = result + s[i] + "#"; return result; } int manacher(string str) { string s = manacherString(str); int R = -1;//最右迴文邊界 int C = -1;//最右迴文邊界對應的中心,隨R的更新而更新。 vector<int> r(s.length());//每個位置的最大回文半徑。 int max = INT_MAX;//記錄最大回文半徑 for (int i = 0; i != s.length(); ++i)//對每一個字元 { r[i] = R > i ? MIN(r[2 * C - i], R - i) : 1;//i位置的最大回文半徑,最起碼的長度 while (i + r[i] < s.length() && i - r[i] >= 0) { if (s[i + r[i]] == s[i - r[i]])//i位置的最大回文子串,還能繼續往外擴; r[i]++; else //擴充套件不了 break;//迴圈結束 } if (i + r[i] > R) { R = i + r[i]; C = i; } if (R == s.length()) { max= r[i]; break; } } return max-1; } string shortestEnd(string str) { int pos = manacher(str); string result = str; for (int i = str.length()-1 - pos; i >=0; --i) { result += str[i]; } return result; } #endif // !