动态规划 😩

                                Dynamic programming

这次想达到的效果是什么?

简单 LV 问题轻松 AC 👏

中等 LV 问题思考 AC 👏

困难 LV 问题  看懂答案思路 🙉

Flag 立的我害怕 🌝🌝

回去总结实践一下,可以达到

哪位勇士 🙌

给动态规划算法下个定义?

引用:

        动态规划是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。

 

动态规划常常适用于有重叠子问题最优子结构性质的问题

 

换而言之,通过历史记录来减少重复计算,而历史记录一般用一维数组 or 二维数组,甚至三维数组进行存储

台阶问题

简单  LeetCode No.70

只讨论 DP 解法

斐波那契数列

1. 定义 DP 数组含义

问题是要求爬 n 级的台阶总共由多少种爬法?

那我定义爬上 i 级台阶 共有 DP[i] 种爬法,

当 i = n 时,DP[n] 是我们想要的值

再想,分解子问题,什么是 DP[n] 的子问题?

DP[n-1]  DP[n-2]... 是 DP[n] 的子问题

以此类推

那我们需要找到 DP[n] 与它的子问题的关系

 

问: 它们具有什么关系?

 

DP[n] = DP[n-1] + DP[n-2]

跳到 第 n 台阶的情况

  • 从 n - 1 台阶跳上来
  • 从 n - 2 台阶跳上来

因为每次只能跳一个台阶,或两个台阶

得出 状态转移方程

状态转移方程

3. 找出初始值

DP[n] = DP[n-1] + DP[n-2]

所以我们要给出 n = 1,n=2 的初始值

n - 2 > 0
DP[1] = 1

万事俱备,写出代码

DP[2] = 2

n=0 为特判

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    if (n === 0) {
        return 0
    }
    let deps = [];
    deps[1] = 1;
    deps[2] = 2;
    for(let i = 3; i <= n; i++) {
        deps[i] = deps[i-1] + deps[i-2];
    }
    return deps[n];
};
O(n)

时间复杂度,空间复杂度

还可以优化一下么?

不同路径

中等  LeetCode No.62

只讨论 DP 解法

杨辉三角

1. 定义 DP 数组含义

当机器人从左上角走到(i, j) 这个位置时,一共有 DP[i] [j] 种路径

2. 给出状态转移方程

走到 S[i][j] 位置的情况:

  1. 从 S[i][j - 1] 走到
  2. 从 S[i - 1][j] 走到
DP[i][j] = DP[i-1][j] + DP[i][j-1]

3. 找到初始值

i - 1>= 0
j - 1 >=0

DP[0][x], DP[x][0] 为我们的初始值

/**
 * @param {number} m
 * @param {number} n
 * @return {number}
 */
var uniquePaths = function(m, n) {
    if (m <= 0 || n <= 0) {
        return 0
    }
    let DP = Array(m).fill(Array(n))
    for(let i = 0; i < m; i++) {
        DP[i][0] = 1
    }
    for(let j = 0; j < n; j++) {
        DP[0][j] = 1
    }
    for(let i = 1; i < m; i++){
        for(let j = 1; j < n; j++) {
            DP[i][j] = DP[i-1][j] + DP[i][j-1]
        }
    }
    return DP[m-1][n-1]
};

时间复杂度

空间复杂度

O(m*n)
O(m*n)

问题来了,怎么优化?

最小路径和

DP[i][j] = min(DP[i-1][j],DP[i][j-1]) + arr[i][j]

最小编辑距离

困难  LeetCode No.72

目标是求解长度为 i 的 word1,转化成 j 长度的 word2, 所使用的最少操作次数为 DP[i] [j]。

1. 定义 DP 数组含义

2. 给出状态转移方程

当 word1[i] 与 word2[j] 相等,我们不需要改操作

word1[i] 与 word2[j] 不相等,我们需要进行,增加,删除,替换三种操作

DP[i][j] = DP[i - 1][j - 1] + 1 替换操作

DP[i][j] = DP[i][j - 1] + 1      插入操作

DP[i][j] = DP[i - 1][j] + 1       删除操作

Why?🙄

DP[i][j] = min(DP[i][j-1],DP[i-1][j], DP[i-1][j-1]) +1
i \ j '' R 0 S
'' 0 1 2 3
R 1
O 2
S 3
E 4

3. 找到初始值

优化?

空间压缩

通过 DP Table 发现

练习题:最长回文字符串  中等

DP[i][j] = true
DP[i-1][j-1] = true
DP[i][j] = (s[i] == s[j] and (j-i > 2) or DP[r-1][j-1])

DP[i][j] 代表 s[i][j] 是否是回文字符串

有没有觉得动态规划并没有想象的那么难呢?😶

虽然遇到难的还是不会,但是我们已经找到了基本的套路。🌝

 ✅ 动态规划
 ❌ 贪心
 ❌ 回溯
分支界定
 分治
  1. 定义 DP 数组含义 难点
    ​目的储存子问题结果
  2. 状态转移方程,也就是元素关系式
  3. 找出初始值

思考三部曲

编码三部曲

  1. 处理特判
  2. 初始化 DP
  3. 实现关系描述 + 边界处理
Made with Slides.com