动态规划通用解题步骤
- 确定dp数组(dp table)以及下标的含义
- 确定递推公式
- dp数组如何初始化
- 确定遍历顺序
- 举例推导dp数组
70. 爬楼梯
核心:第三层只能由第一层迈两步上来,第二层迈一步上来。同时这两种情况还是互斥不重合的。当前情况和之前相关
所有有了状态转移方程dp[i] = dp[i-1] + dp[i-2]。
1. 确定dp数组含义
dp[i]表示到达第i层的方式
2. 确定递推公式
dp[i] = dp[i-1]+dp[i-2]
3. dp数组初始化
dp[1] = 1 dp[2] = 2
4. 确定遍历顺序
自底向上
5. 推导数组看看与实际情况是否相符
dp[1] = 1; [(1)]
dp[2] = 2; [(1,1),(2)]
dp[3] = 3; [(1,2);(1,1,1);(2,1)] ...
6. 代码实现
func climbStairs(n int) int {
dp := make([]int, n + 1)
if n < 2 {
return 1
}
dp[1] = 1
dp[2] = 2
for i := 3; i < n + 1; i ++ {
dp[i] = dp[i-1] + dp[i-2]
}
return dp[n]
}
62. 不同路径
1.确定dp的含义
dp[i][j]: 表示从(0,0)出发到达(i,j)的不同路径
2.确定递推公式
只有这两种来源,同时这两种来源是互斥的 dp[i][j] = dp[i-1][j] + dp[i][j-1]
3.dp数组初始化
dp[i][0] = 1 dp[0][j] = 1
4.确定遍历顺序
5.推导dp数组
6.代码实现
func uniquePaths(m int, n int) int {
// 声明二维数组
dp := make([][]int, m)
for i:=0; i < m; i ++ {
dp[i] = make([]int, n)
}
// 初始化
for j:=0; j < n; j ++ {
dp[0][j] = 1
}
for i:=0; i < m; i ++ {
dp[i][0] = 1
}
// 根据公式向上算
for i:=1 ; i < m; i ++ {
for j := 1; j < n; j++ {
dp[i][j] = dp[i-1][j] + dp[i][j-1]
}
}
return dp[m-1][n-1]
}
343. 整数拆分
1. 确定dp数组的含义
dp[i]: 对于数字i可以得到的最大乘积dp[i]
2. 确定递推公式
发现dp之间的联系有点难 dp[i]的来源
- j * (i-j)---相当于把(i-j)只拆成一个数
- j * dp[i-j]--- 相当于把(i-j)拆分成>=2个数
因此以上为对立事件,涵盖了所有情况,完成了穷举,dp[i]就是记录了最大值,减少了运算次数,减少了穷举数量 dp[i] = max({dp[i], (i - j) * j, dp[i - j] * j})
3. 初始化
dp[2] = 1
4. 确定遍历顺序
5. 手动模拟
输入: n = 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
输入: n = 3
输出:2
解释:3 = 1 * 2; 3 = 1 * 1 * 1 = 1 * dp[2]
输入: n = 4
输出:2
解释:
4 = 3 * 1; 4 = dp[3] * 1
4 = 2*2; 4 = dp[2] * 2
6. 代码实现
func integerBreak(n int) int {
dp := make([]int, n + 1)
dp[1] = 1
dp[2] = 1
for i := 3; i < n + 1 ;i ++ {
for j := 1; j < i ; j ++ {
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
}
}
return dp[n]
}
func max(num1, num2 int) int {
if num1 > num2
return num1
}
return num2
}
96. 不同的二叉搜索树
dp含义
dp[i] 表示i个节点搜索树的种类
递推公式
dp[i]=∑dp[j]∗dp[i−j−1] 其中i中取一个节点为根节点,取j个节点为左子树、剩下的[i-j-1]个节点为右子树
初始化
dp[1]=1
代码
写出来递推公式,代码一般就很简单了..一些四则运算和循环
func numTrees(n int) int {
dp := make([]int, n + 1)
dp[1] = 1
dp [0] = 1
// 起始值注意一下,代入算一下
for i := 2; i < n + 1 ; i++{
for j := 0; j < i; j ++ {
dp [i] += dp[j] * dp[i-j-1]
}
}
return dp[n]
}