题解一: 动态规划
图示:dp[i][j]表示A[i:j] 是否为回文串
复杂度分析:
时间复杂度:O(N^2)
空间复杂度:O(N^2)
实现如下:
class Solution {
public:
int getLongestPalindrome(string A, int n) {
// write code here
int dp[n][n]; // dp[i][j] 表示A[i:j] 是否是回文串
int max_len = 0; //最长回文子串的长度
memset(dp, 0, sizeof(dp));
//从尾到头
for(int i = n-1;i>=0; i--){
//从左到右
for(int j = i;j<n;j++){
int len = j-i+1; //子串长度
if(A[i]==A[j]){ // 如果A[i],A[j]相等
dp[i][j] = len<=2 ? 1 : dp[i+1][j-1]; //len<=2那么就为回文串,len>2: dp[i][j] = dp[i+1][j-1]
}
if(dp[i][j]) max_len = max(max_len,len); //如果A[i:j] 为回文串,那么就从maxlen与len之间取大的
}
}
return max_len;
}
};
题解二:中心扩散
思路: 以一个字符为中心向两边扩散,找出以该字符为中心的最长回文串。
图示:情况a: 回文串长度为奇数; 情况b:回文串长度为偶数
复杂度分析:
时间复杂度:O(N^2)
空间复杂度:O(1)
实现如下:
class Solution {
public:
//向两边扩散,返回最长回文串长度
int kuosan(const string &A,int left,int right,const int &n){
while(left>=0&&right<n&&A[left]==A[right])
{
left--; right++; //向两边扩
}
return right-left-1;
}
int getLongestPalindrome(string A, int n) {
int max_len = 0;
for(int i = n-2;i>=1;i--) //中心位置,注意中心点不会选在0-1之间的中心点,所有循环之后还需要判断中心点选择0-1之间子串
{
int len_1 = kuosan(A,i-1,i+1,n); // 回文串长度为奇数的扩散
int len_2 = kuosan(A,i,i+1,n); // 回文串长度为偶数的扩散,选取i与i+1的中间为扩散开始点
int len = max(len_1,len_2); //取奇数长度回文串和偶数长度回文串
max_len = max(len,max_len); //最后判断max_len与len大小
}
if(A[0]==A[1] && max_len<2) max_len = 2; //判断中心点选择0-1之间子串
return max_len;
}
};
题解三:Manacher
题解思路:Manacher利用了回文串的对称性,插入特殊符号将偶回文串变为奇回文串(如:abba----> #a#b#b#a),并且用一个p数组(半径数组)记录字符串中的字符向左向右扩展的长度。
图示:
计算半径数组p:
复杂度分析:
时间复杂度:O(N) : 只匹配未匹配的位置,对于字符串每个位置只匹配一次。
空间复杂度:O(N)
实现如下:
class Solution {
public:
void manacher(string s,int n,vector<int>& p){
int m = 0;
int m_r = 1; //当前计算回文串的最右端
for(int i = 1;i<n;i++){
if(m_r>i) p[i] = min(p[2*m-i],m_r-i); // 情况1 : 解释: 2*m-i; m到i的距离为i-m. j的位置为 m-(i-m) = 2*m-i;
for(;(s[i+p[i]]==s[i-p[i]] && (i-p[i]>=0)&&(i+p[i]<2*n+1));p[i]+=1){ // 以i点向两边扩展
if(m_r < i + p[i]) //情况1中 p[j] > m_r-i
{
m_r = i+p[i]; //更新最右端值
m = i; //更新m
}
}
}
}
int getLongestPalindrome(string A, int n) {
int max_len = 0;
string s=""; // 存储插入特殊字符之后的字符串
vector<int> p(2*n+1,1);
for(int i = 0;i<2*n+1;i++) //插入特殊字符
{
s.push_back('#');
s.push_back(A[i/2]);++i;
}
manacher(s, 2*n+1, p);
for(auto i : p){
max_len = max(max_len,i-1); //取最大的
}
return max_len;
}
};

京公网安备 11010502036488号