题目:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
思路:
要找最长回文子串,一个子串是不是回文的和内部的子串有关系。如果它内部的子串(同一个对称的地方)又不是回文的,那这个子串肯定不是回文的。
首先对于s[ l :r ]字符串,如果s[ l ] != s[ r ]的话,s[ l :r ]肯定就不是回文串了。当 s[ l ] = s[ r ]时候,再看它里面的字符串,逐步往里走看s[ l+1 :r-1 ]。
看内部字串时候,如果内部 子串只有一个数或者是空的话,这个内部子串肯定是回文的。如果内部有两个及以上的数字,就得接着往下看。也就是r-1 > l+1。
如果已经知道内部子串已经是回文串了,就可以知道当前字符串是回文的了。
class Solution:
def longestPalindrome(self, s: str) -> str:
size = len(s)
if size <= 1:
return s
# 二维 dp 问题
# 状态:dp[l,r]: s[l:r] 包括 l,r ,表示的字符串是不是回文串
# 设置为 None 是为了方便调试,看清楚代码执行流程
dp = [[False for _ in range(size)] for _ in range(size)]
longest_l = 1
res = s[0]
# 因为只有 1 个字符的情况在最开始做了判断
# 左边界一定要比右边界小,因此右边界从 1 开始
# r从头开始,使得算dp[l][r]时候, dp[l + 1][r - 1])已经获得更新。
for r in range(1, size):
for l in range(r):
# 状态转移方程:如果头尾字符相等并且中间也是回文
# 在头尾字符相等的前提下,如果收缩以后不构成区间(最多只有 1 个元素),直接返回 True 即可
# 否则要继续看收缩以后的区间的回文性
# 重点理解 or 的短路性质在这里的作用
# 在首尾相等的情况下,它收缩一次的子串只有一个或者没有字符的情况或者它本身已经是回文字符串了,这个字符串就是回文的。
if s[l] == s[r] and (r - l <= 2 or dp[l + 1][r - 1]):
dp[l][r] = True
cur_len = r - l + 1
if cur_len > longest_l:
longest_l = cur_len
res = s[l:r + 1]
# 调试语句
# for item in dp:
# print(item)
# print('---')
return res