![a2c4b5384146b647a9fb09a37309c43e.png](https://i-blog.csdnimg.cn/blog_migrate/f1d3912dd0cfbc410c93d0582497691e.jpeg)
最近一直想记录下自己学了啥,写文章是个好办法。一方面锻炼自己表述能力,另一方面加强理解。最重要的很多东西看了也是一知半解,希望能得到更多批评指正。
求字符串最大回文子串问题,一般是给出字符串,求给出子串中左右对称的最长子字符串。
例如"dabcba",的回文字符串就是"abcba"。
其解决办法除了,硬怼和动态规划外,还有Manacher算法(马拉车算法)。
马拉车算法时间复杂度一般说是O(n),空间复杂度O(n),是非常高效的一个算法。
其思路如下:
- 调整字符串
因为回文子串有两种可能"aba"和"bb",如果直接处理需要判断子串中心是否有字符。而马拉车算法先为字符串填充无效字符,例如"#"。这样上述字符串就变成"#a#b#a#"和"#b#b#"。这样无论原字符串怎样,新生成的字符串都是长度为奇数,中心有字符。
2. 判断字符半径
这里先引入一些概念和变量。
字符半径:就是以该字符为中心可以形成的最大回文字符串的半径。比如"#a#b#a#"的半径为3。
节点 i :被遍历节点i。
节点maxR : 容纳节点i最大回文子串所覆盖的最大位置。
节点pos : 容纳节点i最大回文子串的中心位置。
节点j : 以pos为中心,节点i的对称位置。
数组R : 记录所有节点为中心的最大回文半径。
之后节点i从左至右遍历字符串,首先预估节点i最小半径,不断扩大搜索范围以确定最终半径。数组R记录下来。最终有了全部回文子串的中心和半径就能确定算法就可以解决。
3. 如何确定节点i的最小半径
如果所有节点i的半径都从0开始枚举,算法复杂度太高。因为在遍历节点i之前,数组R已经记录了过去节点的回文信息。通过maxR和pos记录容纳节点i最大回文子串信息。因为回文子串的左右必然对称,可以估计节点i的半径最小在maxR-i 和其对称节点j半径之间。如图:
![d75e19564cadce6ada3e98ba19e7234f.png](https://i-blog.csdnimg.cn/blog_migrate/8b9a22a9b927689a0310e293ffc21352.jpeg)
公式:
![2a63b03bcf32ad51df3cae5130508d38.png](https://i-blog.csdnimg.cn/blog_migrate/d3706fe0017a345d4b968841a2e338c2.png)
当节点i探索范围超过maxR,则替换maxR和pos。以此遍历完整个字符串后,选择最大子串,保留在奇数位原字符串字符即可。
//
// Created by timruning on 19-4-14.
//
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string manacherAlg(string &x) {
string a = "#";
for (char v:x) {
a.push_back(v);
a.append("#");
}
int pos = 0;
int maxR = 0;
vector<int> R(a.size(), 0);
for (int i = 0; i < a.size(); i++) {
R[i] = maxR > i ? min(maxR - i, R[2 * pos - i]) : 0;
while (R[i] + i < a.size() && i >= R[i] && a[i - R[i]] == a[i + R[i]]) {
R[i] += 1;
}
if (R[i] + i > maxR) {
maxR = R[i] + i;
pos = i;
}
}
int sub[] = {0, 0};
for (int i = 0; i < a.size(); i++) {
if (R[i] > sub[1]) {
sub[0] = i;
sub[1] = R[i];
}
}
string sub2 = "";
for (int i = sub[0] - sub[1] + 1; i <= sub[0] + sub[1] - 1; i++) {
if (i % 2 == 1) {
sub2 += a[i];
}
}
return sub2;
}
int main() {
string x = "waabwswfd";
string result = manacherAlg(x);
cout << result << endl;
}
本文借鉴了 http://www.cnblogs.com/grandyang/p/4475985.html