解题思路
动态规划:填dp表、当前ij状态、过去ij状态、如何联合得到输出、边界条件
1.定义状态:题目让我们求什么,就把什么设置为状态。
2.题目求s中最长的回文子串,那就判断所有子串是否为回文子串,选出最长的。
因此:dp[i][j]表示s[i:j+1]是否为回文子串(这里+1是为了构造闭区间)
状态转移方程:对空间进行分类讨论(当前ij状态、过去ij状态 如何联合得到输出)
当前ij状态:头尾必须相等(s[i]==s[j])
过去ij状态:去掉头尾之后还是一个回文(dp[i+1][j-1] is True)
边界条件:只要是找过去ij状态的时候,就会涉及边界条件(即超出边界情况处理)
当i==j时一定是回文
j-1-(i+1)<=0,即j-i<=2时,只要当s[i]==s[j]时就是回文,不用判断dp[i+1][j-1]
dp[i][j] 为截取的子串
3.初始状态:这里已经直接判断j-i<=2的情况了,因此用不到初始状态,可以不设
4.输出内容:每次发现新回文都比较一下长度,记录i与长度
5.优化空间提速
例子
代码
class Solution:
def longestPalindrome(self, s: str) -> str:
size = len(s)
# 特殊处理
if size == 1:
return s
# 创建动态规划dynamic programing表
dp = [[False for _ in range(size)] for _ in range(size)]
# 初始长度为1,这样万一不存在回文,就返回第一个值(初始条件设置的时候一定要考虑输出)
max_len = 1
start = 0
for j in range(1,size):
for i in range(j):
# 边界条件:
# 只要头尾相等(s[i]==s[j])就能返回True
if j-i<=2:
if s[i]==s[j]:
dp[i][j] = True
cur_len = j-i+1
# 状态转移方程
# 当前dp[i][j]状态:头尾相等(s[i]==s[j])
# 过去dp[i][j]状态:去掉头尾之后还是一个回文(dp[i+1][j-1] is True)
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_len:
max_len = cur_len
start = i
return s[start:start+max_len]
作者:_Breiman
链接:https://leetcode.cn/problems/longest-palindromic-substring/solution/5-zui-chang-hui-wen-zi-chuan-dong-tai-gu-p7uk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
def longestPalindrome(self, s: str) -> str:
n = len(s)
# 特解
if n < 2:
return s
'''
创建动归表dp (n x n的全为False的矩阵) 用来表示字符串s的每一个子串是否为回文
s子串个数 = n + n - 1 + ... + 1, e.g. 字符串babad有5 + 4 + 3 + 2 + 1 = 15种子串
start用来跟踪最长回文子串的起点, max_len代表最长回文子串的长度
'''
dp = [[False] * n for _ in range(n)]
start, max_len = 0, 1
'''
如果字符串是babad
下面的双循环则进行以下遍历 (遍历所有可能的15个子字符串):
b
ba, a
bab, ab, b,
baba, aba, ba, a
babad, abad, bad, ad, d
dp[left][right]代表s被left和right指针相夹而得的子字符串
e.g. left = 0, right = 3, dp[left][right] = baba
'''
for right in range(n):
for left in range(0, right + 1):
'''
(0) 求子串跨越长度span
(1) 边缘情况1: 子串长度为1, 则一定是回文
(2) 边缘情况2: 子串长度为2, 如果俩字符相同则是回文
(3) 非边缘情况则进行动态规划之状态转移: 如果b是回文, aba也一定是回文
即判断是否为回文需同时满足两条件:
1. 剥离左右最外层字符后的子字符串是回文
2. 最外层的字符相同
'''
span = right - left + 1
if span == 1:
dp[left][right] = True
elif span == 2:
dp[left][right] = s[left] == s[right]
else:
dp[left][right] = dp[left + 1][right-1] and s[left] == s[right]
# 若新的回文出现, 判断是否需要更新最大长度
if dp[left][right]:
if span > max_len:
max_len = span
start = left
# 返回最长回文子串
return s[start:start + max_len]
作者:eason734
链接:https://leetcode.cn/problems/longest-palindromic-substring/solution/zui-tong-su-wu-fei-hua-de-pythondong-tai-nysh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。