暴力解法

首先我们来看暴力的解法
例:
图片说明
纯暴力解法:
以每一个字符为回文的中心往两边扩,看能扩出来的最长回文子串是多长(但是这种只局限于长度是奇数的回文子串)
例子中“abba”这种长度为偶数的回文子串就不太好判断了

解决方案:
给字符串添加辅助字符
#a#b#c#1#2#3#4#3#2#1#a#b#b#a#

找到的最长回文子串为
#1#2#3#4#3#2#1#
#a#b#b#a#
除2可以获得原回文子串的长度

代码

class Solution{
public:
    int getLongestPalindrome(string A, int n) {
        string S = "#";
        for(int i = 0 ; i < n ; i ++)
        {
            S+=A[i];
            S+="#";
        }
        vector<int> Len(S.length());
        int ans = 0;
        for(int i = 0 ; i < S.length() ; i++)
        {
            int len = 1;
            while((i-len>=0&&i+len<S.length())&&S[i-len]==S[i+len])
            {
                len++;
            }
            Len[i]=len-1;
            ans = max(Len[i]*2+1,ans);
        }
        return ans/2;
    }
};

但是,如果使用上述暴力解法的话,类似(aaaaaaaaaaaa....aaaaaaaaaaaa)这种情况运行时间会很差

Manancher算法-O(n)时间复杂度解决最长回文子串问题

(马拉车算法)

Step1 给原字符串加辅助字符

Step2 计算以每一个位置为中间的回文子串的长度 (在这里做优化)

我们定义R表示之前访问过的最右的位置
例如:(例子为了看起来方便,没有写出辅助字符)
图片说明
我们当前访问的元素是b,但是之前访问f的时候,回文子串扩到了t的位置
所以R就等于t位置的下标
f位置的下标我们记作Mid(即产出最远位置的中心字符)
F位置对应的回文的回文半径为6

备注:访问时从前往后访问的,所有当我们访问到b的时候,之前的所有元素都访问过了,这个时候我们已经知道之前所有元素能扩展出来的回文半径是多长,以及R是多少。
图片说明
即:①i>=R 暴力
② L_ > L//在边界内 Len[i] = Len[i_]
L_ < L//在边界外 Len[i] = R-i;
L_ == L//相等 从边界开始继续暴力回文判断

c++版本代码

class Solution{
public:
    int getLongestPalindrome(string A, int n) {
        string S = "#";
        for(int i = 0 ; i < n ; i ++)
        {
            S+=A[i];
            S+="#";
        }
        int ans = 0;
        int R = 0;
        int L = 0;
        int Mid = 0;
        vector<int> Len(S.length());
        for(int i = 0 ; i < S.length() ; i++)
        {
            if(i >= R)
            {
                int len = 0;
                while((i-len >=0 && i+len< S.length())&&S[i-len]==S[i+len])
                {
                    len++;
                }
                Len[i] = len-1;
            }
            else{
                int i_ = Mid-(i-Mid);
                int L_ = i_-Len[i_];
                if(L_ > L)//在边界内
                {
                    Len[i] = Len[i_];
                }
                else if(L_ < L)//在边界外
                {
                    Len[i] = R-i;
                }
                else{
                    int len = R-i+1;
                    while((i-len >=0 && i+len< S.length())&&S[i-len]==S[i+len])
                    {
                        len++;
                    }
                    Len[i] = len-1;
                }
            }
            if(i+Len[i] > R)
            {
                Mid = i;
                R = i + Len[i];
                L = i - Len[i];
            }
            ans = max(ans,Len[i]*2+1);
        }
        return ans/2;
    }
};

java

import java.util.*;

public class Solution {
    public int getLongestPalindrome(String A, int n) {
        // write code here
        StringBuffer S = new StringBuffer("#");
        for(int i = 0 ; i < n ; i ++)
        {
            S.append(A.charAt(i));
            S.append("#");
        }
        int ans = 0;
        int R = 0;
        int L = 0;
        int Mid = 0;
        int[] Len = new int[S.length()];
        for(int i = 0 ; i < S.length() ; i++)
        {
            if(i >= R)
            {
                int len = 0;
                while((i-len >=0 && i+len< S.length())&&S.charAt(i-len)==S.charAt(i+len))
                {
                    len++;
                }
                Len[i] = len-1;
            }
            else{
                int i_ = Mid-(i-Mid);
                int L_ = i_-Len[i_];
                if(L_ > L)//在边界内
                {
                    Len[i] = Len[i_];
                }
                else if(L_ < L)//在边界外
                {
                    Len[i] = R-i;
                }
                else{
                    int len = R-i+1;
                    while((i-len >=0 && i+len< S.length())&&S.charAt(i-len)==S.charAt(i+len))
                    {
                        len++;
                    }
                    Len[i] = len-1;
                }
            }
            if(i+Len[i] > R)
            {
                Mid = i;
                R = i + Len[i];
                L = i - Len[i];
            }
            ans = Math.max(ans,Len[i]*2+1);
        }
        return ans/2;
    }
}

python

# -*- coding:utf-8 -*-

class Solution:
    def getLongestPalindrome(self, A, n):
        # write code here
        S = "#"
        for i in range(0,n):
            S+=A[i]
            S+="#"
        ans = 0
        R = 0
        L = 0
        Mid = 0
        Len = [0]*len(S)
        for i in range(0,len(S)):
            if i >= R:
                LEN = 0;
                while i-LEN >=0 and i+LEN< len(S) and S[i-LEN]==S[i+LEN]:
                    LEN=LEN+1
                Len[i] = LEN-1
            else:
                i_ = Mid-(i-Mid)
                L_ = i_-Len[i_]
                if L_ > L:#//在边界内
                    Len[i] = Len[i_]
                elif L_ < L:#//在边界外
                    Len[i] = R-i;
                else:
                    LEN = R-i+1;
                    while i-LEN >=0 and i+LEN< len(S) and S[i-LEN]==S[i+LEN]:
                        LEN = LEN+1
                    Len[i] = LEN-1
            if i+Len[i] > R:
                Mid = i
                R = i + Len[i]
                L = i - Len[i]
            ans = max(ans,Len[i]*2+1);
        return ans//2;