Manacher算法的讲解这里就不说了,网上文献很多,这里给三篇参考:
推荐先看1,然后也许会像我一样有些迷糊,然后看2,看四五次基本就明白了,最后看3,一气呵成。
上代码:
/***********************************************************************************
* 最长回文子串
*
* 系统环境:Deepin Linux 15.6 x64
* 文件名称:longestPalindrome.cpp
* 内容摘要:Manacher算法输出最长回文子串。
* 其他说明:无
* 当前版本:1.0
* 作 者:xjer
* 完成时期:2018.10.30
*
**********************************************************************************/
#include <bits/stdc++.h>
using namespace std;
string preProcess(string str, int len);
string manacher(string str, int len);
/***********************************************************************************
* 功能描述:主函数
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 其他说明:无
*
* ***********************************************************************************/
int main()
{
string str;
cin >> str;
int len = str.length() - 1;
string lgstPalindrome = manacher(str, len);
cout << lgstPalindrome << endl; // 输出最长回文子串
return 0;
}
/***********************************************************************************
* 功能描述:预处理函数
* 输入参数:标准输入str,str的实际长度len
* 输出参数:无
* 返 回 值:预处理后的 tranStr字符串(奇数位)
* 其他说明:1. 转换 str 例:str = "abba", tranStr = "$#a#b#b#a#&". $ 和 & 起哨兵作用,避免边界检查;
* 2. string substr (size_t pos = 0, size_t len = npos)
返回一个新建的初始化为string对象的子串的拷贝string对象。子串是,在字符位置
pos开始,跨越len个字符(或直到字符串的结尾,以先到者为准)对象的部分。
*
* ***********************************************************************************/
string preProcess(string str, int len)
{
if (len == 0)
return "$&";
string ret = "$";
for (int i = 0; i <= len; i++)
{
ret += "#" + str.substr(i, 1);
}
ret += "#&";
//cout << ret << endl;
return ret;
}
/***********************************************************************************
* 功能描述:Manacher算法函数
* 输入参数:标准输入str,str的实际长度len
* 输出参数:无
* 返 回 值:最长回文子串
* 其他说明:算法时间复杂度 O(n)
*
* ***********************************************************************************/
string manacher(string str, int len)
{
string tranStr = preProcess(str, len);
int n = tranStr.length();
/* 数组p[i]记录以字符tranStr[i]为中心的最长回文子串向左/右扩张的长度
(包括tranStr[i],也就是把该回文串“对折”以后的长度)*/
int *p = new int[n];
/* centerId 为已知的 {右边界最大} 的回文子串的中心,
border 则为centerId+p[centerId],也就是这个子串的右边界。*/
int centerId = 0, border = 0;
for (int i = 0; i < n - 1; i++)
{
// symI 是i关于centerId的对称点:symI = centerId - (i - centerId)
int symI = 2 * centerId - i;
// 对于 border <= i 的情况,无法对p[i]做更多的假设,只能p[i] = 1,然后再去匹配。
p[i] = (border > i) ? min(p[symI], border - i) : 1;
while (tranStr[i + p[i]] == tranStr[i - p[i]])
{
p[i]++;
}
if (p[i] + i > border)
{
centerId = i;
border = p[i] + 1;
}
}
//找出p[i]中最大的
int maxLen = 0; // 最长回文子串的长度
int centerIndex = 0; // 对称中心
for (int i = 0; i < n - 1; i++)
{
if (p[i] > maxLen)
{
maxLen = p[i];
centerIndex = i;
}
}
delete[] p;
return str.substr((centerIndex - maxLen) / 2, maxLen);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。