算法刻意练习之动态规划

1 特点

1.1 动态规划和递归或者分治没有根本上的区别(关键看有无最优的子结构)

1.共性:找到重复子问题;
2.差异性:最优子结构、中途可以淘太欠优解

1.2 递归问题一含有重疊的子问题,操作重复

1.记忆化搜索(自顶而下);
2.动态规划(自底而上)

1.3 常识

一般求解最值的问题都可以朝着动态规划的方向去想

2 关键点:

 1.根据最优子结构定义状态:dp[n] = bestOf(dp[n-1], dp[n-2], ...)
 2.递推状态转移方程(DP方程)
   一维:dp[i] = dp[n-1] + dp[n-2]
   二维: dp[i,j] = dp[i+1], i] + dp[i][j+1] (且判断dp[i, j]是否空地)
 3.考虑初始化(base case)
 4.考虑输出
 5.考虑优化空间

3 DP顺推模板

3.1 模板核心

// 模板核心
for 状态1 in 状态1的所有取值:
    for 状态2 in 状态2的所有取值:
        for ...
            dp[状态1][状态2][...] = 择优(选择1,选择2...)

3.2 模板例子

// 模板例子
public void fun(int level, int param) {
    // base case:定义 dp 数组并初始化第 0 行和第 0 列。// 二维情况
    dp = [][]

    // dp:根据状态转移方程 dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 进行递推。
    for i = 0..M {
        for j = 0..N {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
        }
    }
    return dp[M][N]
}

3.3 经典案例

// 62. 不同路径
fun uniquePaths(m: Int, n: Int): Int {
    if (m == 0 || n == 0) return 0

    // base case:定义 dp 数组并初始化第 0 行和第 0 列。// 二维情况
    val dp = Array(m) { IntArray(n) }
    for (i in 0 until m) dp[i][0] = 1
    for (j in 0 until n) dp[0][j] = 1

    // dp:根据状态转移方程 dp[i][j] = dp[i - 1][j] + dp[i][j - 1] 进行递推。
    for (i in 1 until m) {
        for (j in 1 until n) {
            dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
        }
    }
    return dp[m - 1][n - 1]
}

4 思路

4.1 想到动态规划,但又不知从何入手,可以试试这么思考

1.大问题是什么?
2.规模小一点的子问题是什么?
3.它们之间有什么联系?

4.2 例子:一个字符串是否是回文串?

大问题是一个字符串是否是回文串,那规模小一点的子问题呢?
答:一个字符串是回文串,它的首尾字符相同,且剩余子串也是一个回文串。所以,剩余子串是否为回文串,就是规模小一点的子问题,它的结果影响大问题的结果。我们怎么去描述子问题呢?写出

(1)base case:只有一个字母的时候肯定是回文子串,for (i in 0 until n) dp[i][i] = true
(2)db方程:
    // 如果s[i]==s[j],说明只要dp[i+1][j-1]是回文子串,那么dp[i][j]也是回文子串;如果s[i]!=s[j],说明dp[i][j]必定不是回文子串。
    if(s.charAt(i) == s.charAt(j)){
        dp[i][j] = dp[i+1][j-1]
    } else {
        dp[i][j] = false;
    }

5 经典题目

5.1 爬楼梯

在这里插入图片描述

5.2 不同路径

(1)不同路径1
在这里插入图片描述

(2)不同路径2

5.3 打家劫舍

在这里插入图片描述
213. 打家劫舍 II

5.4 最小路径和

在这里插入图片描述

5.5 买卖股票的最佳时机系列

买卖股票的最佳时机 1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6 高阶递归问题

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值