动态规划入门篇

Posted DebugDebut

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态规划入门篇相关的知识,希望对你有一定的参考价值。

入门动态规划的归纳

一、动态规划概念

1. 什么是动态规划

动态规划应用于拥有以下特点的问题:一般需要使用动态规划时,该问题的解可以由更小的解得出,例如:当求单位为n的最优解时,可以转换为求第n-1个单位的最优解······也就是说问题的解可以根据子问题的解求出。

2. 动态规划问题的特点

① 问题具有最优子结构性质。

如果问题的最优解所包含的子问题的解也是最优的,那么该问题具有最优子结构

无后效性。

简单理解:某个子问题的解一旦确定则不会被改变,求其它子问题的解时仅会使用到这些已经确定好的解

3.动态规划的一般思路

① 将原问题分解为子问题

把原问题分解为若干个子问题,子问题的规模比原问题更小,但求解的形式是相似的。

子问题的解一旦求出就会被保存,所以每个子问题的解仅需求解一次

② 确定状态并确定数组(数组维度和长度)

我们往往将子问题的解称为一种“状态”,这种状态的维度一般在确定状态后就可以马上得出,如果这里你不理解没有关系,可以看下面的例题,很好理解~

③ 确定初始(边界)状态的值

随着子问题的不断拆分,最终会到达边界,而边界值是可以直接得出的,称为动态规划的初始值或边界值;

④ 确定状态转移方程(递推公式)

这一步是最重要的!它决定我们能否解决实际问题

找出不同状态之间(前一个子问题与后一个子问题)的关联关系,如何根据之前的状态求出后一个状态,这也可以理解成递推公式

例子:

斐波那契数列求第n项的递推公式:
动态规划入门篇
(可选)⑤ 考虑特殊状态

有些特殊状态并不是适用于状态转移方程中的情况,需要另外拿出来单独考虑并更新状态转移方程,在下面的例题中会遇到这个步骤~

⑥ 编码实现

还是不太懂或者很复杂?没关系,结合题目看看就明白了~在你掌握了入门方法后,这六个步骤就会了如指掌

二、入门例题讲解

类型一、一维dp数组

LeetCode70. 爬楼梯

问题描述:假设你需要爬楼梯,需要爬n阶才能到达楼顶,每次可以爬1或2阶,多少种不同的方法可以爬到楼顶?

① 将原问题分解为子问题

假设n = 5,求爬上第5阶楼梯的最多方法,必定要求出第4阶的最多方法,求第4阶的最多方法,必定要求出第3阶的最多方法······最终求爬上第1阶的最多方法

② 确定状态并确定数组

每一个阶梯都对应一个状态,该状态表示爬上该楼梯的最多方法数值,所以数组维度为1,数组长度为n

③ 边界状态

爬上第1阶楼梯的方法数为1,即爬1阶;

爬上第2阶楼梯的方法数为2,每次爬1阶要爬2次或每次爬2阶爬1次

④ 确定状态转移方程

如何找规律?

手算(少用):列出前面较为容易计算的例子,手写出所有情况,再从中找规律得到状态转移方程。

假设n = 5,则经过手算可以得到如下表格

阶梯数 1 2 3 4 5
方法数 1 2 3 5 8

思想(多用):第n阶可以从第(n-2)阶跨上来或第(n-1)阶爬上来,显然,到达第n阶楼梯的最多方法数等于爬第(n-2)阶的最多方法数加上第(n-1)阶的最多方法数

动态规划入门篇

注意我这里定义的dp数组的下标0位置对应爬上第1阶楼梯的最多方法数而不是第0阶!

⑥ 编码实现

 1class Solution {
2    public int climbStairs(int n) {
3        int[] maxSum = new int[n];
4        for (int i = 0; i < maxSum.length; i++) {
5            if(i == 0){ //第1阶
6                maxSum[i] = 1;
7            }else if(i == 1){ //第2阶
8                maxSum[i] = 2;
9            }else//第3阶及以上
10                maxSum[i] = maxSum[i-1]+maxSum[i-2];
11            }
12        }
13        return maxSum[n-1];
14    }
15}

类型二、二维dp数组

LeetCode62. 不同路径

问题描述:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

问总共有多少条不同的路径?

动态规划入门篇


说明:m 和 n 的值均不超过 100。

① 将原问题拆分为子问题

根据题意:机器人每次只能向下或向右走一步,求走到 [i, j] 位置的最多路径解有两种形式:

(上面格子)[i-1,j] 向下走一步到达[i, j]

(左边格子)[i, j-1]向右走一步到达[i, j]

所以转化为求[i-1, j]和[i, j-1]的最多路径解······

② 确定状态并确定数组

每个格子都有到达自己的最多路径,所以每个到达每个格子的最多路径就是一个状态。

数组:由于格子拥有二维空间(坐标x,坐标y),需要用二维数组存储每个格子的最多路径数,[i,j]代表第i行第j列的格子,dp[i][j]代表到达该格子的最多路径

③边界状态

站在原地有一种走法,就是在原地,所以dp[0][0] = 1;

向右走第一步有一种走法,dp[0][1] = 1    (if m > 1 && n > 1)

向下走第一步有一种走法,dp[1][0] = 1    (if m > 1 && n > 1)

④ 确定状态转移方程

机器人每次可以向右走一步或向下走一步,所以走到第[i, j]格子的最多路径就是可以到达它的所有路径之和
动态规划入门篇

所以可以初步得到状态转移方程:
动态规划入门篇
⑤ 考虑特殊状态

第一行和第一列的所有格子的最多路径都只有1种路径

第一行的格子只能由起点向右走

第一列的格子只能由起点向下走

所以需要更新状态转移方程
动态规划入门篇
⑥ 编码实现

 1package leetcode.动态规划.中等.不同路径;
2
3/**
4 * @author Zeng
5 * @date 2020/1/20 9:34
6 */

7public class Solution {
8
9    public static int uniquePaths(int m, int n) {
10
11        int[][] dp = new int[m][n];
12        for (int i = 0; i < m; i++){
13            for (int j = 0; j < n; j++){
14                //上边界
15                if(i == 0 && j >= 0){dp[i][j] = 1;continue;}
16                //左边界
17                if(j == 0 && i >= 0){dp[i][j] = 1;continue;}
18                //其它情况
19                dp[i][j] = dp[i-1][j] + dp[i][j-1];
20            }
21        }
22        return dp[m-1][n-1];
23    }
24
25    public static void main(String[] args) {
26        int i = uniquePaths(73);
27        System.out.println("最多路径:"+i);
28    }
29
30}
31/**
32  * 最多路径:28
33  */

注意事项:

如果只有一个格子,即(m, n) = (1, 1) ,那么起点就等于终点,也就是一种路径

动态规划入门篇




喜欢本文吗?顺手右上角分享文章

没有关注的小伙伴们关注一波


您小小的举动就是对我们最大的支持!





DebugDebut


动态规划入门篇 

长按二维码 



 

大家想了解什么计算机基础知识也可以私信给我们,我们一定尽量满足您的需求~

再点个在看啦

以上是关于动态规划入门篇的主要内容,如果未能解决你的问题,请参考以下文章

动态规划——入门篇

Java入门算法(动态规划篇1:初识动规)

Java入门算法(动态规划篇1:初识动规)

Java入门算法(动态规划篇2:01背包精讲)

Java入门算法(动态规划篇2:01背包精讲)

初探动态规划(DP)