动态规划中包含3个重要的概念:
- 最优子结构
- 边界
- 状态转移公式。以爬楼梯为例,最优子结构为 ,边界是 ,状态转移公式
斐波那契数列
70. 爬楼梯
本质上为斐波那契数列。递归会超时(python 可设置缓存,不会超时),要用动态规划或直接应用通项公式
定义一个数组 存储上楼梯的方法数(为了方便讨论,数组下标从 开始), 表示走到第 个台阶的方法数目。
第 个台阶可以从第 和 个台阶再走一次到达,走到第 个台阶的方法数为走到第 和第 个楼梯的方法数之和。
198. 打家劫舍
定义 数组用来存储最大的抢劫量,其中 表示抢到第 个住户时的最大抢劫量。
由于不能抢劫邻近住户,如果抢劫了第 个住户,那么就不能再抢劫第 个住户,所以:
衍生题:环形街区
取 和 两者的最大值
矩阵路径
64. 最小路径和
62. 不同路径
排列组合
多重集排列问题
路径方向为多重集,有 向右
和 向下
两种(方向)元素,两种元素的重数分别为 和 ,有 ,则排列数为
⭐动态规划
令 是到达 的路径数,有
数组区间
303. 区域和检索 - 数组不可变
求数组区间 的和
题中强调:会多次调用 sumRange
方法
因此预先求出所有 的和,再 sum[j] - sum[i - 1]
413. 等差数列划分
等差数列满足:至少有 3 个元素、任意两个相邻(隔开不算)元素之差相同
暴力
每一对元素(之间至少隔着一个元素),根据两个元素之间的所有元素差值是否相等来判断是不是等差数列
💣动态规划(想不到这方法)
表示以 为结尾(不是总的)的等差递增子区间的个数,对于 ,有以下结论:
dp[2] = 1
[0, 1, 2]
dp[3] = dp[2] + 1 = 2
[0, 1, 2, 3], // [0, 1, 2] 之后加一个 3
[1, 2, 3] // 新的递增子区间
dp[4] = dp[3] + 1 = 3
[0, 1, 2, 3, 4], // [0, 1, 2, 3] 之后加一个 4
[1, 2, 3, 4], // [1, 2, 3] 之后加一个 4
[2, 3, 4] // 新的递增子区间
综上,在 A[i] - A[i-1] == A[i-1] - A[i-2]
时,dp[i] = dp[i-1] + 1
这里的 不是最终的结果,而是每步的结果。思考的时候过于死板
⭐分割整数
343. 整数拆分
没思路
贪心思想(举例得出规律)
数字 可由 个 和 个 相加而成。是否有优先级最高的因子 存在,有以下判断:
,,因此 比 更优;
,,因此 比 和 更优;
,,因此可以认为 与 等价,因此见到 就拆分;
;因为每个 都可以拆分为 ,而 ,因此见到 就拆分。
;因为 。因此见到 就拆分,并且 是比 更优的因子。
易推出: 大数字都可以被拆分为多个小因子,以获取更大的乘积,只有 和 不需要拆分。 列出以下贪心法则:
- 第一优先级: ;把数字 拆成尽可能多的 之和;
- 特殊情况: 拆完后,如果余数是 ;则应把最后的 替换为 ,因为后者乘积更大;
- 第二优先级: ;留下的余数如果是 ,则保留,不再拆为
当 时,直接返回
动态规划
表示:数字 拆分为至少两个正整数之和的最大乘积。
有转移方程:
由于 时,,所以
279. 完全平方数
BFS
前面有做过
动态规划
表示:数字 拆分为完全平方数的最少个数。
有转移方程:
💣91. 解码方法
字符串中可能包含 "0",因此情况比较复杂
- 若
s[i] == "0"
- 若
s[i - 1] = "1" or "2"
,则 - 否则,
return 0
- 若
- 若
s[i] != "0"
- 若
s[i - 1] == "1"
,则 - 若
s[i - 1] == "2" and "1" <= s[i] <= "6"
,则- 解释:
s[i - 1]
与s[i]
分开译码,为 ;合并译码,为
- 解释:
- 否则,
- 解释:此时若合并译码,则大于 ,
s[i - 1]
与s[i]
只能分开译码
- 解释:此时若合并译码,则大于 ,
- 若
最长递增子序列
300. 最长上升子序列
动态规划
表示以 结尾的序列的最长递增子序列长度。对于每个 ,向前遍历以寻找递增子序列
⭐376. 摆动序列
动态规划
用两个 数组。 表示前 个元素中摆动序列以上升元素结尾的最长子序列长度; 反之。
若第 个元素上升就更新 ,如下代码:( 同理)
if (nums[i] > nums[j]) {
up[i] = Math.max(up[i], down[j] + 1);
}
贪心算法
最长公共子序列
二维数组 用来存储最长公共子序列的长度,其中 表示 的前 个字符与 的前 个字符最长公共子序列的长度,状态转移方程:
特别需要注意的是,当 时,。比如:
abcd
和adbc
当 和 为 时,若用错误的表达式,则最长公共子序列为
⭐221. 最大正方形
这个转移方程想不到
转移方程:
若某格子值为 1 ,则以此为右下角的正方形的、最大边长为:上面的正方形、左面的正方形或左上的正方形中,最小的那个,再加上此格。
⭐0 - 1 背包(难)
此类问题的特点:一般都有选或不选两种选择
不能使用贪心算法
令 表示前 件物品 恰好装入容量为 的背包中所能获得的最大价值。① 第 件物品不放入 ② 第 件物品放入
状态转移方程:
兄弟问题:完全背包问题
416. 分割等和子集
动态规划
表示从数组的 这个子区间内挑选一些正整数,每个数只能用一次,使得这些数的和恰好等于
看题解:这题很好
leetcode-cn.com/problems/pa…
DFS
494. 目标和
01 背包其实不是这种解法的重点,重点是怎么把题目转化成求解 01 背包的形式
本题的 DFS 无法剪枝,为暴力解法
动态规划
思路正常版
递推形式:
由于数组中所有数的和不超过 ,那么 的最小值可以达到 。在很多语言中,是不允许数组的下标为负数的,因此我们需要给 的第二维预先增加