题目大意

给出一个字符串S,找到一个最长的连续回文串。

解题思路

经典讲解参考:
https://www.cnblogs.com/bitzhuwei/p/Longest-Palindromic-Substring-Par-I.html#_labelTop

暴力穷举法O(N3)
显然有C(N,2)(组合)个子串。检测每个子串都需要O(N)的时间,所以此方法的时间复杂度为O(N3)。

动态规划O(N2)时间O(N2)空间
定义二维数组P[i,j]用以表示Si…Sj是回文(true)或不是回文(false)

那么可知状态转移方程:P[i,j] = (P[i + 1, j - 1] && Si ==Sj)

初始条件是:P[i, i] = true,P[i, i + 1] = (Si == Si+1)

这个DP法的思路就是,首先可以知道单个字符和两个相邻字符是否回文,然后检测连续三个字符是否回文,然后四个。

此算法时间复杂度O(N2),空间复杂度O(N2)。

注意:
1.判断空字符串
2.这题遍历切不可横向遍历,否则例如abcba,是无法先将bcb置为1的,进而无法将abcba置为1。
应该如图所示,向右下方先遍历。(后来想想,从下面开始横向遍历也是可以的,只是不可从上面)

class Solution(object):

    def longestPalindrome(self, s):
        """ :type s: str :rtype: str """
        if not s:
            return ''
        # 先将任一单个字母作为结果
        start = 0
        maxlen = 1
        dp = [[0 for __ in range(len(s))] for __ in range(len(s))]
        # 将长度1和长度2(相同字母)情况初始化赋值
        for i in range(len(s)):
            dp[i][i] = 1
            if (i < len(s) - 1) and (s[i] == s[i+1]):
                dp[i][i+1] = 1
                start = i
                maxlen = 2
        # for line in dp:
        # print line
        # 注意:不可横向遍历,否则例如abcba,是无法先将bcb置为1的,进而无法将abcba置为1
        # 从长度3开始
        for length in range(3, len(s)+1):
            for i in range(len(s)-length+1):
                j = i + length - 1
                if (dp[i+1][j-1] == 1) and s[i] == s[j]:
                    dp[i][j] = 1
                    if length > maxlen:
                        start = i
                        maxlen = length
        # for line in dp:
        # print line
        return s[start:start+maxlen]

中心检测法

下面介绍一个O(N2)时间O(1)空间的算法。

回文的特点,就是中心对称。对于有N个字符的字符串S,只有2N-1个中心。

为何是2N-1?因为两个字符之间的空档也可以是一个中心。例如”abba”的两个b中间就是一个中心。

围绕一个中心检测回文需要O(N)时间,所以总的时间复杂度是O(N2)。

class Solution(object):

    def getlongestpalindrome(self, s, l, r):
        while l >= 0 and r < len(s) and s[l] == s[r]:
            l -= 1; r += 1
        return s[l+1 : r]  # 例如bab,最后l=-1,r=3,所以要s[l+1 : r]也就是[0,3] 

    def longestPalindrome(self, s):
        """ :type s: str :rtype: str """
        palindrome = ''
        for i in range(len(s)):
            len1 = len(self.getlongestpalindrome(s, i, i))  # len1是中间是单一字母的回文数
            if len1 > len(palindrome): 
                palindrome = self.getlongestpalindrome(s, i, i)
            len2 = len(self.getlongestpalindrome(s, i, i + 1))  # len2是中间是和后面一个字母相同的回文数
            if len2 > len(palindrome): 
                palindrome = self.getlongestpalindrome(s, i, i + 1)
        return palindrome

总结

  • 回文有两种可能:aba和abba

  • 此题动态规划通过效率不高,不如中心检测法