LeetCode算法题之70. Climbing Stairs(easy)【Python3递归+动态规划题解】

题目描述:
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.

Example 1:

Input: 2
Output: 2
Explanation: There are two ways to climb to the top.

  1. 1 step + 1 step
  2. 2 steps

Example 2:

Input: 3
Output: 3
Explanation: There are three ways to climb to the top.

  1. 1 step + 1 step + 1 step
  2. 1 step + 2 steps
  3. 2 steps + 1 step

题目大意:

  • 给定一个正整数n,代表着阶梯的高度,你每次登阶梯的方式有两种,一个是,一次迈一步,一个是,一次迈两步
  • 让你返回每次都有哪几种可能的方式,登上阶梯顶

解题思路:

  • 第一种思路,递归解法
  • 由题意可知,当给你一个正整数n时,不管n多大,你每次都有两种选择,是迈一步还是迈两步,也就是假如当n=3时,如题目的例子所示,f(3) = f(3-1) + f(3-2) ,f(3) 表示,n=3时,你所能选择的登顶的方式,那么它只能由前一种状态,选择迈一步,或者迈两步
  • 当最后的状态为零时,也就是这种迈步选择方式,真的可以登顶,如果小于零,说明这种方式不行,无法匹配
  • 递归树见下图
    在这里插入图片描述
  • 如果直接按照上图的递归树,编写代码,就是暴力解法,肯定能出答案
  • 但是这里可以更巧妙一些,使递归这种可能包含了很多冗余的重复计算,比如图中的深蓝色部分,如果暴力解法,那这部分,显然就被计算了两次,不划算
  • 在这里,用备忘录(memo)解决这个重复计算
  • 思路是,定义一个字典,用来装每次递归都计算了哪些过程,下次再递归时,先别着急去递归,先去备忘录里面,看看,这个过程有没有被计算过,如果有,那别递归了,太慢,因为都要触底才能向上返回值,直接返回那个存在备忘录里的值
  • 典型的空间换时间,自顶向下解法

少废话,上代码:

class Solution:
    def climbStairs(self, n):
        memo = {}#定义备忘录,用来记录已经计算过的递归树的分支,避免重复计算

        def recursion(n):
            #先去备忘录里看看,算没算过,算过了,直接返回那个算过的值
            if n in memo:
                return memo[n]
            if n == 0:#base case,基础值
                return 1
            if n < 0:#无效方式
                return 0
            memo[n] = recursion(n-1) + recursion(n-2)#每次只有两种选择,上一层台阶还是上两层,递归下去
            return memo[n]#返回那个最后的计算结果

        return recursion(n)

运行时间和内存占用:

  • Runtime: 40 ms, faster than 5.95% of Python3 online submissions for Climbing Stairs.
  • Memory Usage: 13.8 MB, less than 5.97% of Python3 online submissions for Climbing Stairs.

别着急,还可以更快

  • 上动态规划
  • 了解的朋友都知道,首先定义dp数组的含义,一定要清晰明确,不然后根本没法进行,不知道的朋友,没关系,看完,你也会了
  • 我的想法是,直接dp[i] 代表着给定的i层阶梯,所可能达到的所有方式
  • 比如dp[1]=1,代表给定的1层阶梯,登顶的可能方式有1种
  • dp[2]=2,以此类推
  • 其实前面两步,已经将基础案例,也就是base case,给出来了,有了这两个,那么下面无论给定n多大,都可以直接通过for循环,依次加到那个n值
  • 因为是这样,dp[3]等于什么?一定要有这种递推关系,一旦找到,此题一般KO,dp[3]=dp[3-1]+dp[3-2],还是那句话,每次就两种选择,要么迈一步,要么迈两步
  • 想想斐波纳契数列中的定义,和本题是否异曲同工?

少废话,上代码:

class Solution:
    def climbStairs(self, n):
        #定义dp数组并明确概念,dp[i]代表登上i层台阶可能有的所有迈步方式
        dp = []
        dp.append(0)#空着不用,主要是方便数值相互对应上,偏于理解
        dp.append(1)#加初值,base case
        dp.append(2)#同理

        if n == 1:
            return 1
        if n == 2:
            return 2
        if n > 2:
            for i in range(3, n+1):#开始遍历,由递推关系,逐步推出想要结果
                sum = dp[i-1] + dp[i-2]
                dp.append(sum)

        return dp[-1]#最后一个数,即为结果

运行时间和内存占用:

  • Runtime: 32 ms, faster than 26.09% of Python3 online submissions for Climbing Stairs.
  • Memory Usage: 14 MB, less than 5.97% of Python3 online submissions for Climbing Stairs.
********* 自底向上思想 *********
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值