这一篇文章从最简单的动态规划题目开始,结合上一节动态规划三要素,以LeetCode两道基础的DP题目阐述DP问题的基本套路解法。


70. Climbing Stairs

You are climbing a stair case. It takes n steps to reach to the top.

Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?

Note: Given n will be a positive integer.

题目解析:

这是一道最基础的动态规划问题,用于我们初步了解。首先我们来回忆DP三大要素,抽烟喝酒烫头,不,是最优子结构,状态转移方程和边界。

  1. 最优子结构,就是分析问题的关键,构建解题框架。之前以斐波那契数列为例,这次我们以这道题目为例。想知道到达n层台阶,有多少种方式,即f(n)是最终想要的答案,抽象为f(i) 即到达任何一层台阶的方式;所谓子结构,即f(i-1),f(i-2),f(i-3),...,f(2),f(1)。很明显,f(i)的方案数目和 f(i-1)等子问题的答案是有关系的。这就是第一步分析问题我们要做的。
  2. 状态转移方程。f(i)和子问题具体是什么关系呢?这一步要定量分析。由于每次只能走一步或两步,一步之前的台阶在i-1层,两步之前在i-2层,那么第i层的方案数目不就是:f(i) = f(i-1) + f(i-2),(还是斐波那契数列)。这一步定量分析问题和子问题之间的数量关系,
  3. 边界。到这儿就很好理解了,可以定义 f(1)=1, f(2)=2.
  4. 其实还有第四步,就是编码啦,能把你的思路写出来才行。

下面我们看代码实现,在dp问题中,对于f(i)我们一般存为数组dp.

class Solution:def climbStairs(self, n: int) -> int:# 特殊情况if n <= 2:return n# dp数组必备dp = [0] * (n+1)# 边界dp[1] = 1dp[2] = 2for i in range(3, n+1):# 状态转移方程dp[i] = dp[i-1] + dp[i-2]return dp[-1]        

这个一维的问题就图森破了,下面我们看经典的二维dp问题。说来说去,二维不一定比一维的就难,一维的数组也有很多难题。

62. Unique Paths

A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).

The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).

How many possible unique paths are there?

题目解析:

我们仿照上题的思路来解析,看三大要素。f(i,j)表示到达i行j列的路径数,f(m,n)即最终结果。i行j列是从左侧或上边走过来的,必然有一定的最优子结构的形式。那么接下来分析状态转移方程。和上一题类似,i行j列的上一步或者在i-1行j列,或者在i行j-1列,只有这两种情况,且每种情况下只有一条路径到i,j,因此直接得到f(i,j) = f(i-1,j) + f(i,j-1)。二维问题的边界也在二维数组的边界,下面我们直接看代码实现:

class Solution:def uniquePaths(self, m: int, n: int) -> int:# dp数组dp = [[0] * n for _ in range(m)]# 边界for i in range(m):dp[i][0] = 1for i in range(n):dp[0][i] = 1for i in range(1, m):            for j in range(1, n):# 状态转移方程dp[i][j] = dp[i-1][j] + dp[i][j-1]return dp[m-1][n-1] # 或dp[-1][-1]

再额外解释一下边界,沿着第一行或者第一列都是只有一种路径,所以边界的初始值都是1,也可以直接把dp数组初始化为1.


先充分的消化一下上面两道问题的dp套路,从三要素理解解题思路,进而理解dp的核心思想,最优子结构和无后效性。

根据无后效性,下面我们看一下dp算法的优化思路。

以climbing stairs为例,基本思路中我们定义了长度为n的数组用于存储i处的最终解,时间复杂度O(n);但是从关系式dp[i] = dp[i-1] + dp[i-2]可以看出,在i处我们只需要i-1和i-2的值,更早的值我们不需要了,这就体现了无后效性,因此我们只需要三个变量即可解决问题,下面看代码:

class Solution:def climbStairs(self, n: int) -> int:if n <= 2:return npre1 = 2pre2 = 1dp = 0for i in range(3, n+1):            dp = pre1 + pre2pre2, pre1 = pre1, dpreturn dp        

就是这样,将空间复杂度降到了O(1)。我们再看unique paths题目的优化。

对于第i行第j列,我们看关系式 f(i,j) = f(i-1,j) + f(i,j-1),在前面的解法中,我们的空间复杂度是O(m*n),对于每个位置来说,我们需要左边的和上边的,对于每一行来说,我们只需要上一行的结果即可。因此我们可以将空间复杂度降到O(n),结合下面代码来看,我们只定义一个一维dp数组,在每行遍历中,不断更新dp数组的值,不断抛弃上一行的结果,直到最后一行。

class Solution:def uniquePaths(self, m: int, n: int) -> int:# 定义一维dp数组,同时初始化了第一行的边界值dp = [1] * nfor i in range(1, m):            for j in range(n):# 第一列的边界if j == 0:dp[j] = 1else:# 相当于原状态转移方程,不断更新dp数组值dp[j] += dp[j-1]return dp[-1]

10.2 动态规划算法套路及空间优化 —— Climbing Stairs Unique Paths相关推荐

  1. 程序员的算法课(5)-动态规划算法

    前言 众所周知,递归算法时间复杂度很高为(2^n),而动态规划算法也能够解决此类问题,动态规划的算法的时间复杂度为(n^2).动态规划算法是以空间置换时间的解决方式. 一.什么是动态规划 动态规划(D ...

  2. 贪心算法,递归算法,动态规划算法比较与总结

    一般实际生活中我们遇到的算法分为四类: 一>判定性问题        二>最优化问题        三>构造性问题        四>计算性问题 而今天所要总结的算法就是着重解 ...

  3. 动态规划算法之资源分配问题及其空间优化方案

    资源分配问题:某厂根据计划安排,拟将n台相同的设备分配给m个车间,各车间获得这种设备后,可以为国家提供盈利Ci j(i台设备提供给j号车间将得到的利润,1≤i≤n,1≤j≤m).问如何分配,才使国家得 ...

  4. 01背包问题的动态规划算法、蛮力法和空间优化算法

    算法思想: (1).动态规划算法:解决背包物品价值最大化问题的最优解,是建立在每一个子问题的最优解的前提下完成的.设Value[i,j]表示的是i个物品放进背包容量为j的背包的价值,令i从0增至n(物 ...

  5. 以空间换时间——动态规划算法及其应用:矩阵链相乘

    动态规划算法是5大算法基础中最重要的一个,它专门用来解决平面世界下的应用,即会多次使用二维数组. 当然动态规划算法是空间换时间的算法,也就是说:我们可以利用空间资源来使某算法问题的时间复杂度降到最低. ...

  6. 算法套路学习笔记(第二章) 动态规划系列 2.13-2.19

    完整博文地址 由于CSDN的图片导入机制的问题,导致在本地编写的md文档中的图片无法上传到CSDN上,因此我把博文push到了gitee上,以下是地址:请点击:我的博文地址 2.14 经典动态规划:戳 ...

  7. 动态规划算法的优化技巧

    动态规划是信息学竞赛中一种常用的程序设计方法,本文着重讨论了运用动态规划思想解题时时间效率的优化.全文分为四个部分,首先讨论了动态规划时间效率优化的可行性和必要性,接着给出了动态规划时间复杂度的决定因 ...

  8. [剑指offer]面试题第[60]题[JAVA][n个骰子的点数][动态规划][空间优化]

    [问题描述][中等] 把n个骰子扔在地上,所有骰子朝上一面的点数之和为s.输入n,打印出s的所有可能的值出现的概率.你需要用一个浮点数数组返回答案,其中第 i 个元素代表这 n 个骰子所能掷出的点数集 ...

  9. 使用动态规划算法需要满足的必要条件:优化原则

    1.动态规划的定义 动态规划算法:多阶段决策过程,每步求解的问题是后面阶段求解问题的子问题,每步决策将依赖于以前步骤的决策结果: 2.使用动态规划技术的必要条件:满足优化原则 优化原则: 一个最优决策 ...

最新文章

  1. 自己写的thinkphp自动生成类
  2. git安装与配置_git 安装及基本配置
  3. Node.js module.exports与导出
  4. [知识库:python-tornado]异步调用中的上下文控制Tornado stack context
  5. Camtasia 2021mac版
  6. 阶段3 1.Mybatis_08.动态SQL_02.mybatis中动态sql语句-where标签的使用
  7. java面试题 springmvc 解决post get请求乱码问题
  8. TensorFlow基础知识:计算图中的Op,边,和张量
  9. SQLServer 不允许保存更改的解决办法
  10. iconfont图标本地使用
  11. 2016年9月学习总结与反思
  12. mysql 中一个表里有父子关系_SQLAlchemy - 同一个表中的父子关系
  13. mysql替代符号,mysql特殊符号
  14. JavaWeb之servlet(1)
  15. LikeLib:区块链+云计算的结合技术现在成熟了吗?
  16. centos 6.2 安装intel 显卡驱动
  17. 求圆周长、圆面积、圆球表面积、圆球体积、圆柱体积(基础作业
  18. 通过游戏策划阶段防治游戏外挂
  19. 机电一体化概论【1】
  20. 艺术家与AI研究者的跨界碰撞丨记青源Workshop「AI+艺术」研讨会(2022年第10期)...

热门文章

  1. 万字长文带你感受Tesla AI Day 2022-特斯拉自动驾驶FSD
  2. laravel接口+微信小程序调用
  3. php 转驼峰,PHP实现驼峰和下划线互转
  4. python大驼峰_python中什么是驼峰法
  5. PK!一个优秀程序员的自我修养
  6. 利用tomcat服务器,数据库,jsp,html实现用户注册
  7. 马光远:当前房地产产能严重过剩 80%开发商将倒闭
  8. 365天挑战LeetCode1000题——Day 071 阶乘后的零 阶乘函数后 K 个零 最小栈 移除无效的括号
  9. Python爬取小说网站总推荐排行榜所有小说~
  10. 2014年重要的软件开发发展