5. 最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = “babad”
输出:“bab”
解释:“aba” 同样是符合题意的答案。
示例 2:
输入:s = “cbbd”
输出:“bb”
示例 3:
输入:s = “a”
输出:“a”
示例 4:
输入:s = “ac”
输出:“a”
可以使用从中心往两边的找法,以每一个点为中心,依次往两边扩展;也可以使用动态规划。
1、中心往两边
重点是注意考虑中心是1一个数还是两个数!!
class Solution(object):
def longestPalindrome(self, s):
def palindrome(i, j):
out = 0
while i >= 0 and j <= len(s) - 1:
if s[i] == s[j]:
i -= 1
j += 1
out += 2
else:
break
i += 1
j -= 1
return out, s[i:j+1]
if not s:
return ""
out = 0
longest = 0
for i in range(len(s)):
out1, sub1 = palindrome(i, i+1) # 从前往后移动
out2, sub2 = palindrome(i-1, i+1) # 从中间往两边
out2 += 1
out = max(out1, out2)
if out > longest:
longest = out
if out == out2:
sub_str = sub2
else:
sub_str = sub1
return sub_str
动态规划
首先,dp[i][j]代表的是s[i:j+1]是否是回文子串。
状态转移方程:
dp[i][j] = (s[i] == s[j]) and dp[i + 1][j - 1]
为什么是这个方程,我们可以通过画表格看出,
举例: 对于abbba,我们想看s[0:5],那么其实取决于s[1:4],因为只有s[1:4]是回文子串,那么s[0:5]才是回文子串。
这道题与以往有点不同的是,遍历的顺序有所改变,因为我们需要先得到dp[i+1][j-1],所以我们的遍历顺序是先对j进行遍历,再对i进行遍历。相当于从上往下进行的。
class Solution(object):
def longestPalindrome(self, s):
# 动态规划
dp = []
for i in range(len(s)):
dp.append([0]*len(s))
longest = 0
sub_str = s[0]
for j in range(len(s)):
for i in range(0, j):
if s[i] == s[j]:
if i+1 >= j-1:
dp[i][j] = 1
else:
dp[i][j] = dp[i+1][j-1]
if dp[i][j]:
if j - i > longest:
longest = j-i
sub_str = s[i:j+1]
return sub_str
得到二维的表示之后自然要优化空间:需要注意的是,上一子串是回文串并不代表目前的子串是回文串,所以当s[i] != s[j]的时候,就必须手动将dp[i][j] = 0。
class Solution(object):
def longestPalindrome(self, s):
# 动态规划
dp = [0]*len(s)
longest = 0
sub_str = s[0]
for j in range(len(s)):
for i in range(j+1):
if i == j:
dp[i] = 1
elif s[i] == s[j]:
if i+1 > j-1:
dp[i] = 1
else:
dp[i] = dp[i+1]
if dp[i]:
if j - i > longest:
longest = j-i
sub_str = s[i:j+1]
else:
dp[i] = 0 # 上一波虽然可能是1,但是现在不是回文子串了,所以必然是0,切记修改~
return sub_str
另外一种解法:
相当于长度递增,从1到… 然后从左到右遍历。这样就可以使得每个区间都可以得到遍历,并且依次扩大。
def solution(nums):
n = len(nums)
dp = []
for i in range(n):
dp.append([""]*n)
for i in range(n):
dp[i][i] = 1
mini = n-1
minj = n-1
for length in range(1, n):
for i in range(n):
j = i + length
if j >= n:
break
if nums[i] == nums[j]:
if j == i + 1:
dp[i][j] = 1
if j - i > minj - mini:
mini, minj = i, j
else:
if dp[i+1][j-1]:
dp[i][j] = 1
if j-i > minj - mini:
mini, minj = i, j
return minj-mini+1