139. 单词拆分
- 题意: 判断一个 s 能不能由一个 wordDict 组成
- 思路: 一维动态规划
dp[i]
:s[0:i]
是否能被组成- 对于每个
dp[i]
, 去找有没有一个分割位置j
能够让前半部分能被组成且后半部分在字典中
- 代码:
1 | def wordBreak(self, s: str, wordDict: List[str]) -> bool: |
300. 最长递增子序列
- 题意: 找无需连续的最长递增长度
- 思路: 一维动态规划
dp[i]
: 以num[i]
为结尾的最长长度 (初始值为 1)- 对于每个
dp[i]
, 去找[0, i-1]
范围内比自己 num 小的 dp 最大值 + 1
- 代码:
1 | def lengthOfLIS(self, nums: List[int]) -> int: |
42. 接雨水
- 思路: (动态规划版)
- 对于每个索引,求左侧最高柱子高度和右侧最高柱子高度 (包括自己!)
- 对于每个索引,其最大储水量: 左右柱子取较小值 - 当前柱子高度 (特判负数!)
- 代码:
1 | def trap(self, height: List[int]) -> int: |
5. 最长回文子串
- 题意: 找到给定字符串中的最长回文子串(连续), 返回子串
- 思路: 二维动态规划
dp[i][j]
:s[i:j+1]
是否为回文串 (i
,j
相当于左右边界)- 初始:
- 当
i==j
时, 就是单个字符, 肯定为True
- 当
i+1==j
时, 就是两个字符, 判断s[i]==s[j]
- 当
- 转移:
dp[i][j]
取决于两个条件:s[i]==s[j]
(边界是否相等)dp[i+1][j-1]
(除开左右边界, 内部的是否为回文串)
i
需要从下往上遍历 (转移时主要关注左下角的状态, 画个草图即可理解)
- 最后答案需要遍历一下
dp
二维数组, 找到最长的回文子串
- 代码:
1 | def longestPalindrome(self, s: str) -> str: |
516. 最长回文子序列
- 题意: 找到给定字符串中的最长回文子序列(不连续), 返回长度
- 思路: 二维动态规划
dp[i][j]
:s[i:j+1]
内的最长回文子序列的长度 (i
,j
相当于左右边界)- 初始:
- 当
i==j
时, 就是单个字符, 肯定为True
- 当
i+1==j
时, 就是两个字符, 判断s[i]==s[j]
- 当
- 转移:
- 当
s[i]==s[j]
,dp[i][j] = dp[i+1][j-1] + 2
- 当
s[i]!=s[j]
,dp[i][j] = max(dp[i][j-1], dp[i+1][j])
- 当
- 代码:
1 | def longestPalindromeSubseq(self, s: str) -> int: |