题解一: 动态规划
图示: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;
    }
};