动态规划(英语:Dynamic programming,简称 DP)是通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。
动态规划常常适用于有重叠子问题和最优子结构性质的问题,并且记录所有子问题的结果,因此动态规划方法所耗时间往往远少于朴素解法。
动态规划有自底向上和自顶向下两种解决问题的方式。自顶向下即记忆化递归,自底向上就是递推。
使用动态规划解决的问题有个明显的特点,一旦一个子问题的求解得到结果,以后的计算过程就不会修改它,这样的特点叫做无后效性,求解问题的过程形成了一张有向无环图。动态规划只解决每个子问题一次,具有天然剪枝的功能,从而减少计算量。
题目:给你一个字符串 s,找到 s 中最长的回文子串。
我的错误答案:
class Solution:
def longestPalindrome(self, s: str) -> str:
lst1 = [i for i in s]
def ab(slst):
lst = []
for idx, i in enumerate(slst):
if i in lst:
lst.append(i)
return lst
else:
lst.append(i)
if idx == len(slst)-1:#说明整个字符串都没有重复字符
return lst[0]
else:
continue
lst2 = ab(lst1)
lst3 = ab(lst2[::-1])
result = "".join(lst3[::-1])
return result
想法:从前到后遍历,直到有重复字符,生成到此为止的列表。然后再将列表反过来遍历,直到有重复字符,截停。
错误原因:要求返回最长回文子串,这意味着需要比较长度。未通过例子是:“ccc”,应该返回"ccc",我返回了"cc"。
正确解答:补充:如何将列表的元素反过来?
第一种:list.reverse();
第二种:list[::-1]
解题思路:回文串的特性:
动态规划思路设计:
在状态转移方程中,我们是从长度较短的字符串向长度较长的字符串进行转移的,因此一定要注意动态规划的循环顺序。
考虑边界:
返回值:
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
if n < 2:
return s
max_len = 1
begin = 0
# dp[i][j] 表示 s[i..j] 是否是回文串
dp = [[False] * n for _ in range(n)]
for i in range(n):
dp[i][i] = True
# 递推开始
# 先枚举子串长度
for L in range(2, n + 1): ## L是子串长度
# 枚举左边界,左边界的上限设置可以宽松一些
for i in range(n):## i是左边界
# 由 L 和 i 可以确定右边界,即 j - i + 1 = L 得
j = L + i - 1
# 如果右边界越界,就可以退出当前循环
if j >= n:
break
if s[i] != s[j]:
dp[i][j] = False
else:
if j - i < 3:
dp[i][j] = True
else:
dp[i][j] = dp[i + 1][j - 1]
# 只要 dp[i][L] == true 成立,就表示子串 s[i..L] 是回文,此时记录回文长度和起始位置
if dp[i][j] and j - i + 1 > max_len:
max_len = j - i + 1
begin = i
return s[begin:begin + max_len]



