算法学习(十七)动态规划

动态规划

1. 概念

记忆化搜索:递归搜索 + 保存中间计算结果,如何思考状态转移是重点

递归:1:1 翻译 DFS 为 DP

三步走 🔥

  • 思考回溯怎么写:① 入参是什么;② 递归到哪里;③ 注意递归边界和入口
  • 改成记忆化搜索
  • 1:1 翻译成递推:① dfs 改成 dp 数组;② 递归改成循环;③ 递归边界对应 dp 数组的初始化

时间复杂度:状态个数 * 单个状态计算时间

2. 解题技巧(我的总结)

1> 复杂问题无法一次性状态转移的可以分成多个子问题,分别进行状态转移,最后合并结果, (或者仅对其中一个子问题状态转移)

题目说明实现
764. 最大加号标志分成四个方向分别求解我的提交
838. 推多米诺分成两个个方向分别转移我的提交
1031. 两个非重叠子数组的最大和仅对(i:)区间内长度为firstlen和secondLen的最大长度状态转移我的提交
1139. 最大的以 1 为边界的正方形分别求解四个方向连续1的个数我的提交
1525. 字符串的好分割数目分别求解i左右边不同字符的个数我的提交
1749. 任意子数组和的绝对值的最大值分别求解子数组的最小和和最大和,简化状态转移我的提交
1888. 使二进制字符串字符交替的最少反转次数看成左右两个部分分别为交替串,从左到右、从右到左分别求解,细分成为0/1结尾的交替串两个子状态我的提交
123. 买卖股票的最佳时机 III分成求解某一点左边卖出能获得的最大收益 + 某一点右边买入能获得的最大收益 之和我的提交

2> 使用两个变量滚动记录 dp,优化空间

题目说明实现
70. 爬楼梯只记录上一个状态我的提交

3> 一个状态划分两个或以上的子状态,分别对每个子状态进行转移,合并得到结果

题目说明实现
357. 统计各位数字都不同的数字个数划分是/否含0两个状态我的提交
714. 买卖股票的最佳时机含手续费划分是/否持有股票两个状态我的提交
576. 出界的路径数划分网格位置 m*n 个状态我的提交
494. 目标和划分当前和 1000 + 1 + 1000 个状态我的提交
740. 删除并获得点数排序后划分 是/否 选择当前数 2 个状态我的提交
926. 将字符串翻转到单调递增当前位分别为 ‘0’,‘1’ 时符合条件的最优值我的提交
935. 骑士拨号器长度为i的号码划分成从0~9开始的10个子状态,每个子状态之间通过马字形转移我的提交
1155. 掷骰子等于目标和的方法数dp(i)(j)表示第i次累计和为j的种类数,1=<j<=target我的提交
1186. 删除一次得到子数组最大和dp(i)(0),dp(i)(1)分别表示前i个元素,删除和不删元素的最大子数组和我的提交
1262. 可被三整除的最大和dp(i)(0),dp(i)(1), dp(i)(2)分别表示前i个元素%3的最大和我的提交
1504. 统计全 1 子矩形dp(i,j,h) 表示右下端点为ij, 高度为h的矩形的最大宽度, dp(i,j,h) = dp(i,j-1,h) + 1我的提交
1567. 乘积为正数的最长子数组长度dp(i)(0), dp(i)(1)分别表示i结尾乘积正/负数的最长子数组长度我的提交
1594. 矩阵的最大非负积dp(i)(j)(0), dp(i)(j)(1)分别表示i,j位置累积非负/负的绝对值最大的乘积我的提交
1638. 统计只差一个字符的子串数目dp(i)(j)(0), dp(i)(j)(1)分别表示以i,j位置结尾累积相同/差1字符的最长子串长度我的提交
1824. 最少侧跳次数划分成青蛙在三个跑道上的侧跳次数分别进行状态转移我的提交
[188. 买卖股票的最佳时机 IV](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/description/划分成持有股票和不持有两个自状态,对k和i进行[我的提交](https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/submissions/487402940/
[1223. 掷骰子模拟](https://leetcode.cn/problems/dice-roll-simulation/description/划分成6个数结尾,每个结尾再划分结尾连续相同数量(1~rollMax),分别进行状态转移[我的提交](https://leetcode.cn/problems/dice-roll-simulation/submissions/492484131/

4> 可对状态进行分类(26个字母等)、对数据进行排序等,从而大大减少时间

题目说明实现
467. 环绕字符串中唯一的子字符串针对26个字母分类巧妙去重我的题解
2008. 出租车的最大盈利根据到达地点从小到大排序我的题解
940. 不同的子序列 II记录26个字母最后出现的位置,探索每个字符结尾的序列数目,不关心它们之间的重复,最终答案是26个字母最后出现位置的结尾序列数目之和我的题解
2405. 子字符串的最优划分记录26个字母倒数第二次出现的位置,每次取26个位置中最大的那个后面可以划分为一个我的题解

5> 区间类型的动态规划

题目说明实现
553. 最优除法除法 = 左区间 / 右区间我的提交
516. 最长回文子序列当前区间 = 左端点 + 子区间 + 右端点我的提交
1039. 多边形三角剖分的最低得分当前区间 = 左区间 + 三角形 + 右区间我的提交
1130. 叶值的最小代价生成树当前区间最优 = min(左区间最优 + 右区间最优 + 左区间最大值*右区间最大值)我的提交
[312. 戳气球](https://leetcode.cn/problems/burst-balloons/description/(i,j)区间全部戳破分数 = score(i,mid) + score(mid,j) + num[mid]*num[i]*num[j]我的提交
[375. 猜数字大小 II](https://leetcode.cn/problems/guess-number-higher-or-lower-ii/description/(i,j)区间内确定的最小花费 = (i,mid-1) + (mid+1,j) + mid + 1我的提交
[664. 奇怪的打印机](https://leetcode.cn/problems/strange-printer/description/一定是优先打印两端的字符更好,两端字符不相等的话必然分成左右两个区间分别打印,两端相等则最后一个字符不用特地打印我的提交

6> 根据题意使用多维动态规划

题目说明实现
873. 最长的斐波那契子序列的长度使用二维状态表示以i和j位置结尾的最长长度我的提交
1027. 最长等差数列使用二维状态表示以i和j位置结尾的最长长度我的提交
87. 扰乱字符串可以分解成子问题,s1、s2位置、长度三维动态规划我的提交
474. 一和零dp(k,i,j) 表示前k个中限制0,1为i,j分别能得到的最大子集数目,集合问题一般就是考虑max(取当前元素后前面的最大值+1,不取当前元素时前面的最大值)我的提交
[1463. 摘樱桃 II](https://leetcode.cn/problems/cherry-pickup-ii/description/三维动态规划,二维数组表示两个机器人位置我的提交

7> 求概率问题从小规模下的概率递推到大规模条件的概率

题目说明实现
808. 分汤知道A=0&B=0的概率,A=0&B>0的概率,递推至A=N,B=N我的提交

8> 博弈游戏类型(当前用户最优选择 = max(当前选择 + 当前选择导致的状态下当前用户(即另一用户)最优选择))

题目说明实现
486. 预测赢家抽象成当前用户和下一用户之间的状态转移,利用区间类型动态规划我的提交
464. 我能赢吗类似的思路,使用记忆化搜索的方法我的提交
1140. 石子游戏 IIdp(i)(j) 表示玩家在stones(i:)开始选择,M=j时能获得的最多分数我的提交
2029. 石子游戏 IXLoss() 表示当前玩家无论做任何选择都会输,则Loss返回False的前提是某个选择后对手Loss返回true我的提交

9> 当前状态可能由前面一个或多个特定状态转移得到,根据题目条件分析

题目说明实现
823. 带因子的二叉树排序数组,依次求每个节点为树根的情况我的提交
907. 子数组的最小值之和i为右端点的所有子数组最小值之和 = 上一个更小元素(位置j)为右…之和 + arr[i]*(i-j)我的提交
983. 最低票价第i天最低消费 = min( (1天票+前i-1天最低消费),(7天票+前i-7天最低消费),(30天票+前i-30天最低消费) )我的提交
1024. 视频拼接以每个片段结尾的消耗的片段 = 能和当前片段开头拼接上的所有片段结尾的片段数+1 (此题,易错点较多)我的提交
1048. 最长字符串链先排序, 当前最长链 = max(删除每个字母后的新word在前面的链长 + 1)我的提交
1105. 填充书架当前本之前的最优 = min(从当前本往前k本放在一行 + i-k之前的最优 ) (k=1,2…)我的提交
1578. 使绳子变成彩色的最短时间dp[i] = min(移除i + dp[i-1], 移除上一与i不同的j处的dp[j] + 移除前(i-j-1)的cost)我的提交
1621. 大小为 K 的不重叠线段的数目dp(i)(k) 表示i点前 分配 k段绳子的方法数我的提交
1626. 无矛盾的最佳球队对队伍双重排序(相同年龄按分数排),大大简化算法我的提交
1696. 跳跃游戏 VI使用大顶堆优化对前面k个状态最优的查找我的提交
1884. 鸡蛋掉落-两枚鸡蛋i楼时往第j层扔一个鸡蛋,碎了则N=1+(i-1), 没碎则N=[j+1:i]区间所需次数(即dp[0:i-j]) + 1,取二者较大值(从j=1开始不断增加即可)我的提交
1959. K 次调整数组大小浪费的最小总空间划分成2段,总段在k情况最少使用空间 = 后一段的最大值 + 前一段在k-1情况下的最少使用空间 (后一段长度从1逐渐增大)我的提交
140. 单词拆分 II最后一个单词 + 前面的dp我的提交
446. 等差数列划分 II - 子序列以j,k结尾的序列 可以由 前面特定若干个的i元素导致的 i,j结尾的序列数 + 1我的提交
518. 零钱兑换 II前i个coin组合成amount的组合数由前i-1个coin组成amount-coin,amount-2*coin,…的组合数 转化而来我的提交
795. 区间子数组个数要同时记录以i结尾的不超过right的连续子数组数目,不然会漏掉很多解我的提交
960. 删列造序 III即求一个字符串的最长上升序列动态规划问题,限制转移条件要对所有字符串满足即可我的提交
1029. 两地调度逐个遍历costs,记录前i个面试者在A地个数分别为minA,maxA的最小花费我的提交
2054. 两个最好的不重叠活动分成选择1个和选择2个的最大收益两个子状态分别根据最先满足endtime<starttime的结果转移我的提交
410. 分割数组的最大值划分为k个数组的最优值可以由:前面若干划分为k-1个 + 后面若干个为一组 的情况转变而来我的提交
2266. 统计打字方案数新状态 = 前面某个状态 + 最后一个字符,只需考虑dp[i] 可否由 dp[i-1], dp[i-2], dp[i-3], dp[i-4]转换而来我的提交

10> 我称之为状态扩散,从某个状态按规则扩散到其余新状态

题目说明实现
1162. 地图分析某位置距离陆地d,则其上下左右的海洋距离陆地d+1,扩散至没有海洋我的提交
1947. 最大兼容性评分和mark第j位表示第j个教授是否被选择,mark中有k个1,初始时mark=0,从每个mark扩散到含k+1的mark我的提交

11> 节点距离问题,使用动态规划、贝尔曼福特算法
每轮循环知道相邻 f -> t 之间的距离c,对其余节点i(i!=f && i!=t):
if c + d(t)(i) < d(f)(i) 则更新d(f)(i)
!!! 不要忘了还有: c + d(f)(i) < d(t)(i) 则更新d(t)(i)

题目说明实现
1334. 阈值距离内邻居最少的城市求出每个节点间最小距离我的提交
1311. 获取你好友已观看的视频求出每个好友间最小距离我的提交

12> 状态压缩dp,通常用于数组A和数组B任意匹配问题

题目说明实现
1947. 最大兼容性评分和mark第j位表示第j个教授是否被选择,mark中1的数量k表示现在为第k个学生匹配教授我的提交
1986. 完成任务的最少工作时间段子集型状态压缩我的提交
2305. 公平分发饼干子集型状态压缩我的提交

13> 倒序动态规划

题目说明实现
174. 地下城游戏dp(i,j)表示i,j到终点所需的最小初始值我的提交

14> 线性dp

题目说明实现
1269. 停在原地的方案数记录各个位置的方案数,当前位置方案由上一位置±1/不变转换来我的提交
1449. 数位成本和为目标值的最大数字记录各个target的最大字符串,当前位置方案由上一位置+v转换来我的提交
2400. 恰好移动 k 步到达某一位置的方法数目线性dp,只需记录离终点距离k以内的数组(长度2k+1),不断减小k,newDp[i] = dp[i-1] + dp[i+1]我的提交

14> 数型dp

题目说明实现
LCP 34. 二叉树染色记录各个节点为根有连续i个节点的最大值(i取值从0到k),优化:i越小越有价值,dp[i]取前i个中的最大值我的提交

3. 更多练习

题目说明题解
1043. 分隔数组以得到最大和枚举最后一段的子数组下标 j,dfs(i) 表示 arr[0…i] 做分隔变换得到的最大元素和0x3F
1105. 填充书架dfs(i) 表示摆放 books[0…i] 可以做到的最小高度,枚举最后一层可以放置的书通过
1335. 工作计划的最低难度dfs(i, j) 表示 j 天完成 job[0…i] 的最小难度,有限制的枚举最后一个天的工作 job[k…i] 取最大值 mx通过
1416. 恢复数组dfs(i) 表示 s[0…i] 字符串分割成数组的方案数,枚举末尾段字符子串 t 可能得分割方式,不能含有前导 0 并且不能超过 k通过

4. 参考

  • 26
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值