给你一个字符串 s,找到 s 中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
#我们用 P(i,j) 表示字符串 s 的第 i 到 j个字母组成的串(下文表示成 s[i:j])是否为回文串:
#也就是说,只有 s[i+1:j−1] 是回文串,并且 s的第 i和 j 个字母相同时,s[i:j] 才会是回文串。
#首先 用一个二维数组 dp表示子问题P(i,j) 的解,其中 dp[i][j] = true 表示子串 s[i:j] 是回文串,dp[i][j] = false 表示子串 s[i:j] 不是是回文串
#如果 s[i] 和 s[j] 相同,并且子串 s[i+1:j-1] 是回文串,那么子串 s[i:j] 也一定是回文串。
#如果 s[i] 和 s[j] 相同,并且j-i<3,即子串的长度小于等于3,那么子串 s[i:j] 也一定是回文串。
#如果 s[i] 和 s[j] 相同,j-i>=3,即子串的长度大于3,那么就需要根据子问题 P(i+1,j-1) 的解(True或者False)来判断子问题 P(i,j) 的解。
#如果 s[i] 和 s[j] 不相同,那么子串 s[i:j] 一定不是回文串。
#然后,从长度为 2 的子字符串开始,依次枚举长度为 2、3、4……的子字符串,判断它们是否为回文串。
#对于长度为 2 的子字符串,只需要判断两个字母是否相同即可。
#计算最大回文子串的长度和起始位置
def longestPalindrome(s):n = len(s)if n < 2:return smax_len = 1begin = 0# 动态规划计算每个子字符串是否为回文串## dp[i][j] 表示 s[i..j] 是否是回文串dp = [[False] * n for _ in range(n)] # 二维列表 每个列表有n个元素 初始化为 Falsefor i in range(n):# 单个字符都是回文串dp[i][i] = True# 从长度为2的子字符串开始,依次递增for L in range(2, n + 1):# 枚举子字符串的起始位置 左边界for i in range(n):# 枚举子字符串的结束位置 右边界j = i + L - 1 #从长度为 2 的子字符串开始,依次枚举长度为 2、3、4……的子字符串# 如果右边界越界,就可以退出当前循环if j >= n:breakif s[i] != s[j]:# 如果子字符串的第一个字符和最后一个字符不相同,则不是回文串dp[i][j] = Falseelse:# 如果子字符串的长度小于 3,则直接判断if j - i < 3: #这种情况下 不需要判断子问题dp[i][j] = Trueelse:# 如果子字符串的长度大于等于 3,则判断子字符串的子问题# 子问题与原问题除了子字符串的起始位置和结束位置之外,其他都相同#回文串 满足两个条件 只有 s[i+1:j−1] 是回文串,并且 s的第 i和 j 个字母相同时,s[i:j] 才会是回文串。dp[i][j] = dp[i + 1][j - 1]# 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置if dp[i][j] and j - i + 1 > max_len:max_len = j - i + 1begin = ireturn s[begin:begin + max_len]if __name__ == '__main__':s = "bcabacd"print(longestPalindrome(s))