问题描述
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
解题思路
滑动窗口由小到大。
1
2
3
4
5
6
7
8
9
10
11
12 | class Solution:
def longestPalindrome(self, s: str) -> str:
left = max_len = 0
n = len(s)
for i in range(n):
for j in range(i, n):
t = s[i : j + 1]
k = len(t)
if t == t[::-1] and k > max_len:
max_len = k
left = i
return s[left : left + max_len]
|

结果超时。
滑动窗口由大到小。因为是计算最长回文,在上面第二层循环中,可以让 j 递减,这样只要当前的字符串是回文,它就是以 i 为起点的最长回文。
1
2
3
4
5
6
7
8
9
10
11
12
13 | class Solution:
def longestPalindrome(self, s: str) -> str:
left = max_len = 0
n = len(s)
for i in range(n):
for j in range(n - 1, i - 1, -1):
t = s[i : j + 1]
if t == t[::-1]:
if len(t) > max_len:
max_len = len(t)
left = i
break
return s[left : left + max_len]
|

结果超时。但是通过的测例更多了一点。
再改进一下。
第 i 次循环得到的最大回文长度为 max_len,第 i+1 中,j 只用从 n-1 到 i+1+max_len 就行,否则 j 再小得到的最大回文长度也不会超过 max_len 了。
1
2
3
4
5
6
7
8
9
10
11
12 | class Solution:
def longestPalindrome(self, s: str) -> str:
left = max_len = 0
n = len(s)
for i in range(n):
for j in range(n - 1, i + max_len - 1, -1):
t = s[i : j + 1]
if t == t[::-1]:
max_len = len(t)
left = i
break
return s[left : left + max_len]
|

在超时边缘徘徊,第一次看到运行时长这么长的并且还通过了。
若 s[i:j] 为回文,则 s[i+1:j-1] 如果存在也是回文,这说明到达当前位置时的最长回文,最多比之前的最长回文多 2 个字符,所以每次我们在位置 i,可以只判断:
s[i-max_len:i+1](长度为 max_len+1)是否为回文
s[i-max_len-1:i+1](长度为 max_len+2)是否为回文
即可。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | class Solution:
def longestPalindrome(self, s: str) -> str:
idx, max_len = 0, 1
for i in range(1, len(s)):
s1 = s[i - max_len : i + 1]
s2 = s[i - max_len - 1 : i + 1]
if i - max_len - 1 >= 0 and s2 == s2[::-1]:
idx, max_len = i, max_len + 2
continue
if i - max_len >= 0 and s1 == s1[::-1]:
idx, max_len = i, max_len + 1
return s[idx - max_len + 1 : idx + 1]
|
