动态规划入门篇
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(7, 3);
27 System.out.println("最多路径:"+i);
28 }
29
30}
31/**
32 * 最多路径:28
33 */
注意事项:
如果只有一个格子,即(m, n) = (1, 1) ,那么起点就等于终点,也就是一种路径
喜欢本文吗?顺手右上角分享文章
没有关注的小伙伴们关注一波
您小小的举动就是对我们最大的支持!
DebugDebut
长按二维码
大家想了解什么计算机基础知识也可以私信给我们,我们一定尽量满足您的需求~
再点个在看啦
以上是关于动态规划入门篇的主要内容,如果未能解决你的问题,请参考以下文章