647.回文子串【连续子序列】
=动规五部曲==
- 确定dp数组(dp table)以及下标的含义
布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串,如果是,dp[i][j]为true,否则为false
- 确定递推公式
情况一:下标i 与 j相同,同一个字符例如a,当然是回文子串
情况二:下标i 与 j相差为1,例如aa,也是回文子串
情况三:下标:i 与 j相差大于1的时候,例如cabac,此时s[i]与s[j]已经相同了,我们看i到j区间是不是回文子串就看aba是不是回文就可以了,那么aba的区间就是 i+1 与 j-1区间,这个区间是不是回文就看dp[i + 1][j - 1]是否为true。- dp数组如何初始化 dp[i][j]初始化为false
- 确定遍历顺序,i 从大到小, j从小到大
class Solution:
def countSubstrings(self, s: str) -> int:
dp = [[False] * len(s) for _ in range(len(s))]
result = 0
for i in range(len(s)-1, -1, -1): #注意遍历顺序
for j in range(i, len(s)):
if s[i] == s[j]:
if j - i <= 1: #情况一 和 情况二
result += 1
dp[i][j] = True
elif dp[i+1][j-1]: #情况三
result += 1
dp[i][j] = True
return result
516.最长回文子序列【不连续子序列】
=动规五部曲==
- 确定dp数组(dp table)以及下标的含义
布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串,最长的回文子序列
2.递归公式
if (s[i] == s[j]) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]);
}
- dp数组初始化
i=j dp[i][j] =1 其他dp[i][j]初始化为0就行- 遍历顺序
class Solution:
def longestPalindromeSubseq(self, s: str) -> int:
dp = [[0] * len(s) for _ in range(len(s))]
for i in range(len(s)):
dp[i][i] = 1
for i in range(len(s)-1, -1, -1):
for j in range(i+1, len(s)): #注意是i+1
if s[i] == s[j]:
dp[i][j] = dp[i+1][j-1] + 2
else:
dp[i][j] = max(dp[i+1][j], dp[i][j-1])
return dp[0][-1]
动态规划最强总结篇
-
背包问题【01背包+完全背包】
-
打家劫舍
-
买卖股票的最佳时机
-
子序列问题【连续+ 不连续 + 回文 + 编辑距离】