https://leetcode-cn.com/problems/climbing-stairs/

一 题目

假设你正在爬楼梯。需要 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 阶

二 递归分析

这是典型的递归类问题,这类问题的核心就是数学归纳法:
当 n = 1 时,上楼梯的方式:从0阶爬1阶。
当 n = 2 时,上楼梯的方式:①从0阶(2-2)爬2阶;②从1阶(2-1)爬1阶。
当 n = 3 时,上楼梯的方式:①从1阶(3-2)爬2阶;②从2阶(3-1)爬1阶。
……
当 n = k 时,上楼梯的方式:①从k-2阶爬2阶;②从k-1阶爬1阶。
因此,要求爬上 n 阶楼梯的方式,就是求爬 n-1 阶梯的方式与爬 n-2 阶梯的方式之和。
函数就是:f(n) = f(n-1)+f(n-2)
递归方式就很显然了,递归的终结点就是 n-1 = 1 或 n-1 =2 时

三 递归解题方法-1

1. 代码

  1. package top.black.leetcode.s0070climbStairs;
  2. class Solution {
  3. public int climbStairs(int n) {
  4. return climb(n);
  5. }
  6. private int climb(int n){
  7. if(n == 1){
  8. return 1;
  9. }else if(n == 2){
  10. return 2;
  11. }
  12. return climb(n-1)+climb(n-2);
  13. }
  14. public static void main(String[] args) {
  15. Solution solution = new Solution();
  16. System.out.println("1阶:"+solution.climbStairs(1));
  17. System.out.println("2阶:"+solution.climbStairs(2));
  18. System.out.println("3阶:"+solution.climbStairs(3));
  19. System.out.println("4阶:"+solution.climbStairs(4));
  20. System.out.println("5阶:"+solution.climbStairs(5));
  21. System.out.println("6阶:"+solution.climbStairs(6));
  22. }
  23. }

2. 存在的问题

当 n 越大时,递归的深度会越深,因此需要进行的计算次数也越多,导致当n达到一定程度时,运行的测试用例会超出时间限制。
image.png
思考:为什么会出现这样的情况?有什么地方是我们没有想到的?
再回忆递归的过程:
f(n) = f(n-1) + f(n-2);
f(n-1) = f(n-2) + f(n-3);f (n-2) = f(n-3)+f(n-4);
f(n-3) = f(n-4)+f(n-5);f(n-4) = f(n-5)+f(n-6);
……
此时我们应该要发现,在进行递归f(n)时,f(n-1) 会计算 f(n-2) 和 f(n-3) 的结果,然后又计算了一遍 f(n-2) 的结果,然后求和。然后这样树形展开下去,会发现,整个程序计算中,存在着大量的计算重复值的过程,而这些重复计算,会浪费我们大量的内存和时间,因此,需要对这部分过程进行优化。

四 递归解题方法-2优化

我们可以将已经计算好的结果存储在一个hashmap或者数组中,只有取不到值的时候,才进行计算。

1. 代码

  1. package top.black.leetcode.s0070climbStairs;
  2. class Solution {
  3. int []num ;
  4. public int climbStairs(int n) {
  5. num = new int[n+1];
  6. return climb(n);
  7. }
  8. private int climb(int n){
  9. if(n == 1){
  10. return 1;
  11. }else if(n == 2){
  12. return 2;
  13. }
  14. // 1. 先从数组中取值,看是否为0
  15. // 如果为0,则代表没计算过
  16. // 如果不为0,则直接返回取出的值
  17. int sum = num[n];
  18. if(sum>0){
  19. return sum;
  20. }
  21. // 计算出当前层结果
  22. sum = climb(n-1)+climb(n-2);
  23. // 存储到数组中
  24. num[n] = sum;
  25. return sum;
  26. }
  27. public static void main(String[] args) {
  28. Solution solution = new Solution();
  29. System.out.println("1阶:"+solution.climbStairs(1));
  30. System.out.println("2阶:"+solution.climbStairs(2));
  31. System.out.println("3阶:"+solution.climbStairs(3));
  32. System.out.println("4阶:"+solution.climbStairs(4));
  33. System.out.println("5阶:"+solution.climbStairs(5));
  34. System.out.println("6阶:"+solution.climbStairs(6));
  35. }
  36. }

2. 执行结果

image.png