整理一下刷题过程中的一些想法,方便以后高效复习,动态规划部分整理如下:
主要的思路有如下几种:
基础类型
- 只需要写出i和i-1之间的状态转移方程即可,没有任何额外操作的行为,比如:
- 一维度:
- 高维度:
-
120. 三角形最小路径和,状态方程是:
dp[k][z] = min((dp[k-1][z]+triangle[k][z]),(dp[k-1][z-1]+triangle[k][z]))
-
63. 不同路径 II,状态方程是:
obstacleGrid[i][j] = obstacleGrid[i][j - 1] + obstacleGrid[i - 1][j]
-
64. 最小路径和,状态方程是:
mat[i][j] = min(mat[i - 1][j], mat[i][j - 1]) + grid[i][j]
-
221. 最大正方形,状态方程是:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
-
中间变量类型
- 需要额外借助第三方变量进行中间值判断的:
- 121. 买卖股票的最佳时机,状态方程是:
Math.max(profit, prices[i] - Math.min(minprofit, prices[i]));
- 139. 单词拆分,状态方程是:
dp[j] = True if dp[i] and s[i:j] in wordDict
- 264. 丑数 II,状态方程是:
int minval = Math.min(last_2,Math.min(last_3,last_5));
- 121. 买卖股票的最佳时机,状态方程是:
定制判断类型
- 带有定制化的判断条件的:
- 72. 编辑距离,状态方程条件是:
word1[j-1]==word2[i-1]
- 85. 最大矩形,状态方程条件是:
matrix[i][j] != '0'
- 91. 解码方法,状态方程条件是:
s[i] != "0"和s[i - 1] != "0" and int(s[i - 1:i + 1]) <= 26
- 152. 乘积最大子序列,状态方程条件是:
MAX, MIN = MIN, MAX if nums[i] < 0
- 300. 最长上升子序列,状态方程条件是:
if (nums[i] > nums[j]) {dp[i] = Math.max(dp[i], dp[j] + 1);}
- 338. 比特位计数,状态方程条件是:
if (i%2==1){ans[i] = ans[i-1]+1;} else {ans[i] = ans[i/2];}
- 72. 编辑距离,状态方程条件是:
倒叙逆向类型
- 174. 地下城游戏,状态转移方程是:
dp[i][j] = max(1, min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j])
反方向的的递归,比较打破常规思维
循环判断类型
- 在dp的基础上需要再遍历已经扫过的数组。此类方法的复杂度一般较高:
- 279. 完全平方数,状态转移方程是:
while i - j ** 2 >= 0:
dp[i] = min(dp[i], dp[i - j ** 2] + 1)
j += 1
预处理类型
- 740. 删除与获得点数
这题麻烦在预处理每一个值,因为值有可能重复:
target = [0] * (max(nums) + 1)
for num in nums:
target[num] += num
之后的转移方程反而非常简单:d[i] = max(d[i - 1], d[i - 2] + target[i])
技巧类型
这题在于要想到把字符转化对应的ASCII码,转移方程:array[ord(c)-ord("a")]=sum(array)+1
,除此之外还需要想到新增一个字母等于当前所有字母后面可加+单独自身,这个方程确实非常非常有技巧
以上为LeetCode中比较有代表性的一些题目,把这些搞懂之后可以解决绝大多数dp的类似题型,以2020校招为例:
携程 - Deep learning Engineer
给定一个时刻表,根据目的地进行分组,同一个目的地必须尽可能的多分,不能打乱顺序,比如aabbcddc,需要分成aa|bb|cddc,而不能分成aabb|cddc,因为这种情况下不是最多,也不能分成aa|bb|c|dd|c,因为相同的c没有被分在一起;求分组个数;
这题就是典型的循环判断类型+中间变量类型,需要储存历史遍历结果并多次查询,代码解答
Tencent - Deep learning Engineer
花匠摆花问题,两个坑:
1.用traceback的就直接gg,比如我
2.dp[i]为当前的长度为i的可摆放个数,dp[i] = dp[i-1]+dp[i-k]为状态转移矩阵,更多解释看代码注释
这题就是简单的基础类型,唯一难的地方是要想到i-k这个dp结果
Dynamic Programming 动态规划就给大家整理到这,如果大家想看更多的数据结构问题,可以关注一下我的Github,希望有所帮助。
欢迎大家关注我的个人bolg,知乎,更多代码内容欢迎follow我的个人Github,如果有任何算法、代码、转行疑问都欢迎通过邮箱发消息给我。