背景

这道题之前刷过,记得是一道非常基础的动态规划题,但怎么也没有想出来该怎么做这道题。

题目

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。

示例 1:
输入: 2
输出: 2

解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 1 阶
2.  2 阶

示例 2:
输入: 3
输出: 3
解释: 有三种方法可以爬到楼顶。

1.  1 阶 + 1 阶 + 1 阶
2.  1 阶 + 2 阶
3.  2 阶 + 1 阶

来源:力扣(LeetCode)

思路

我们可以从最后一步往前推:现在我们在第n阶,那么我们要到达第n阶,应该怎么做呢?
  最后一步走一步,或者两步。那么爬上n阶楼梯的方法数=爬上n-1阶楼梯的方法数(最后爬一步) + 爬上n-2阶楼梯的方法数(最后爬两步)

解决方法一:递归

class Solution {  
  public int climbStairs(int n) {  
    return doClimb(0, n);  
  }  
  
  private int doClimb(int i, int n) {  
      if (i == n)  
        return 1;  

      if (i == n - 1)  
        return 1;  
      
      return doClimb(i + 1, n) \+ doClimb(i + 2, n);  
     }  
}

这种方式在leetcode上跑的时候会超时,时间复制读为O(2^n)。

解决方法二:带备忘录的递归算法

在上面一种算法中,随着n的增大,计算量会急剧膨胀,通过leetcode的观察会发现在n=44时超时。
在下面的算法当中,我们增加一个Map结构用来存储曾经计算过的结果,下次在计算相同的内容时,我们先查询Map中是否已经计算过了,如果计算过了就直接把结果取出来用。

import java.util.HashMap;

class Solution {
    // 备忘录记录从i阶到n阶有多少种方法
    private HashMap<Integer, Integer> memento = new HashMap<>();

    public int climbStairs(int n) {
        return doClimb(0, n);
    }

    private int doClimb(int i, int n) {
        if (i == n || i == n - 1)
            return 1;
        int marchWithOneStep;
        if (!memento.containsKey(i + 1)) {
            marchWithOneStep = doClimb(i + 1, n);
            memento.put(i + 1, marchWithOneStep);
        } else {
            marchWithOneStep = memento.get(i + 1);
        }

        int marchWithTwoStep;
        if (!memento.containsKey(i + 2)) {
            marchWithTwoStep = doClimb(i + 2, n);
            memento.put(i + 2, n);
        } else {
            marchWithTwoStep = memento.get(i + 2);
        }

        return marchWithOneStep + marchWithTwoStep;
    }
}

解决方法三:动态规划

动态规划是把计算过程中变量的值作为一种状态来看的算法,最终要计算的结果是由前面计算出来的中间状态计算出来的。
在该题中,从0阶爬上n阶的方法 = 从0阶爬到n-1阶 + 从0阶爬到n-2阶。

class Solution {
    public int climbStairs(int n) {
        if (n == 1)
            return 1;

        int[] nums = new int[n];
        nums[0] = 1;
        nums[1] = 2;
        for (int i = 2; i < nums.length; i++) {
            nums[i] = nums[i - 1] + nums[i - 2];
        }
        return nums[n - 1];
    }
}

水一水
39 声望5 粉丝

总结经验,提升自己