5. 最长回文子串
原始题目链接:https://leetcode-cn.com/problems/longest-palindromic-substring/
给你一个字符串 s,找到 s 中最长的回文子串。
解题思路:
使用动态规划思路解题。定义状态dp[i][j]表示字符串s的子串s[i: j + 1](字符串第i个字符到第j个字符的闭区间的子串)是否是回文串,所以初始化动态方程数组dp[][]的值使用布尔运算符False,特别地对角线表示i和j是相等的,即单个字符,肯定是回文,所以初始化的时候赋值为True。当前状态需要判断首尾两个字符是否相等:s[i] == s[j],过去状态dp[i + 1][j - 1],就是前后各缩减一个字符,如果当前状态的首付两个字符都相等并且过去状态是回文串,那当前状态肯定也是回文串即d[i][j]为True。考虑边界条件,当右边索引小于左边索引的时候,即j - 1 -(i + 1)<= 0时,等价于j - i <= 2,如下图的对角线左下方的情况,从图中可以看出对角线满足s[i] == s[j],左下方的情况继续判断s[i] == s[j]的情况,满足就是回文串。对角线右上方的情况,根据当前状态和过去状态来判断是否为回文串。每次判断完更新开始索引和最大长度的值。具体实现看代码及注释。以s=“babab”为例子的状态图:
代码实现:
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
# 字符串小于2,单个或空字符,返回s即可
if n < 2:
return s
# dp[i][j]表示s[i:j+1]是否是回文串
# 初始化dp数组,对角线i=j,s[i:j+1]表示相同的字符肯定是回文串,则为True
dp = [[False]*n for _ in range(n)]
for i in range(n):
dp[i][i] = True
# 初始化最大回文字符串的开始和结束索引为1和0
# 这样s[begin_index, begin_index + max_index]就表示第一个字符
max_index, begin_index = 1, 0
# 开始遍历s,分为边界条件和非边界条件
for j in range(1, n):
for i in range(j):
# 边界条件:j-1 - (i + 1) <= 0,即j - i <= 2
if j - i <= 2:
# 只需要判断s[i]是否等于s[j]
if s[i] == s[j]:
dp[i][j] = True
# 记录当前子串的长度
cur_len = j - i + 1
# 非边界条件,就要判断首尾字符是否相等和上一个状态是否是回文串
else:
if s[i] == s[j] and dp[i + 1][j - 1] :
dp[i][j] = True
cur_len = j - i + 1
if dp[i][j]:
if cur_len > max_index:
max_index = cur_len
begin_index = i
return s[begin_index: begin_index + max_index]
参考文献:
https://leetcode-cn.com/problems/longest-palindromic-substring/solution/5-zui-chang-hui-wen-zi-chuan-dong-tai-gu-p7uk/