一、647. 回文子串
题目链接:647. 回文子串 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——647. 回文子串
视频讲解:动态规划,字符串性质决定了DP数组的定义 | LeetCode:647.回文子串_哔哩哔哩_bilibili
动态规划五部曲:
1. 确定 dp 数组及下标含义:dp[ i ][ j ] 表示 [ i, j ] 范围内的子串是否是回文子串,bool类型,用一个 result 统计回文子串个数
2. 确定递推公式:
if s[ i ] == s[ j ]:
# case1. i == j,一定是回文子串,如a
# case2. i, j 相差1,一定是回文子串,如aa
if j - i <= 1:
dp[ i ][ j ] = True
result += 1
# case3. j - j > 1,看 [ i + 1, j - 1 ] 是不是回文子串
elif dp[ i + 1 ][ j - 1 ] == True:
dp[ i ][ j ] = True
result += 1
3. 确定dp数组如何初始化:全部初始化为False
4. 确定遍历顺序:需要[ i + 1, j - 1 ],从下向上,从左向右遍历
for i in range(len(s) - 1, -1, -1):
for j in range(i, len(s)):
递推公式
5. 举例推导dp数组。
class Solution:
def countSubstrings(self, s: str) -> int:
# 初始化全为False的dp数组
dp = [[False] * len(s) for _ in range(len(s))]
reslut = 0
# 从下向上遍历
for i in range(len(s) - 1, -1, -1):
for j in range(i, len(s)):
if s[i] == s[j]:
# case1. case2.
if j - i <= 1:
dp[i][j] = True
reslut += 1
# case3.
elif dp[i + 1][j - 1] == True:
dp[i][j] = True
reslut += 1
return reslut
二、516. 最长回文子序列
题目链接:516. 最长回文子序列 - 力扣(LeetCode)
文章讲解:代码随想录 (programmercarl.com)——516. 最长回文子序列
视频讲解:动态规划再显神通,LeetCode:516.最长回文子序列_哔哩哔哩_bilibili
动态规划五部曲:
1. 确定 dp 数组及下标含义:dp[ i ][ j ] 表示[ i, j ] 内的回文子序列长度。结果dp[0][-1],即从0开始到最后一个元素结束的回文子串长度。
2. 确定递推公式:
if s[ i ] == s[ j ]:
dp[ i ][ j ] = dp[ i + 1 ][ j - 1 ] + 2
else:(分别考虑每一个元素情况)
dp[ i ][ j ] = max(dp[ i ][ j - 1](考虑s[ i ]), dp[ i + 1 ][ j ](考虑s[ j ]))
3. 确定dp数组如何初始化:从两端向中间遍历,最中间遍历不到,所以初始化 dp[ i ][ i ] = 1,即当i = j时,初始化为1
4. 确定遍历顺序:从下向上,从左向右遍历
for i in range(len(s) - 1, -1, -1):
for j in range(i + 1, len(s)):
递推公式
5. 举例推导dp数组。
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):
# j 一定大于 i,从i + 1开始,j = i已经初始化了
for j in range(i + 1, len(s)):
if s[i] == s[j]:
dp[i][j] = dp[i + 1][j - 1] + 2
else:
dp[i][j] = max(dp[i][j - 1], dp[i + 1][j])
return dp[0][-1]
三、动态规划总结篇