题目:
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
思路
我们可以使用动态规划来解决这个问题。具体地,设状态 dp[i][j] 表示字符串 s 的子串 s[i:j+1] 是否为回文串。那么,如果 s[i:j+1] 是回文串,那么 s[i+1:j] 也一定是回文串,即 dp[i+1][j-1] = True;否则,s[i:j+1] 不是回文串。
注意到一个回文串去掉首位字符后仍然是回文串。因此,我们可以根据子串的长度进行推导。具体地,对于每个 i 和 j,我们首先判断 s[i] 和 s[j] 是否相等。如果相等,那么如果 s[i+1:j] 是回文串,那么 s[i:j+1] 也一定是回文串;否则,s[i:j+1] 不是回文串。如果 s[i] 和 s[j] 不相等,那么 s[i:j+1] 不是回文串。
当子串长度为 1 或者 2 时,容易推出其是否为回文串。因此,我们可以从子串长度为 3 开始逐步向上推导,直到整个字符串。最终,最长回文子串即为所有 dp[i][j] = True 中最长的一个。
代码实现
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
n = len(s)
dp = [[False] * n for _ in range(n)]
ans = ""
# 枚举子串长度 l+1
for l in range(n):
for i in range(n):
j = i + l
if j >= n:
break
if l == 0:
dp[i][j] = True
elif l == 1:
dp[i][j] = (s[i] == s[j])
else:
dp[i][j] = (s[i] == s[j] and dp[i+1][j-1])
if dp[i][j] and l + 1 > len(ans):
ans = s[i:j+1]
return ans
在上面的代码中,我们首先创建一个二维数组 dp,并初始化所有的 dp[i][j] = False(默认不是回文串)。随后,我们依次枚举子串的长度 l+1 和起始位置 i,并计算结束位置 j。如果子串的长度为 1 或者 2,则容易计算其是否为回文串。否则,我们需要根据状态转移方程 dp[i][j] = (s[i] == s[j] and dp[i+1][j-1]) 来判断该子串是否为回文串。
由于每个状态只与其左下方的状态有关,因此可以使用滚动数组将空间复杂度优化到 O(n)。总时间复杂度为 O(n^2),其中 n 是字符串 s 的长度。