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

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

注意:给定 n 是一个正整数。

示例 1:

  1. 输入: 2
  2. 输出: 2
  3. 解释: 有两种方法可以爬到楼顶。
  4. 1. 1 + 1
  5. 2. 2

示例 2:

  1. 输入: 3
  2. 输出: 3
  3. 解释: 有三种方法可以爬到楼顶。
  4. 1. 1 + 1 + 1
  5. 2. 1 + 2
  6. 3. 2 + 1

动态规划

由于第一步有1、2两种可能,那么可以得出爬楼梯 - 简单 - 图1,这时候千万别陷入递归的泥潭,而要考虑是否递归,一般而言,递归的两个分因子是独立的,而递推的两个分因子是有联系(如f(x-2)是构成f(x-1)的一个因子,爬楼梯 - 简单 - 图2,这时候应该考虑一下是否能够递推。

  1. class Solution {
  2. public int climbStairs(int n) {
  3. if(n <= 0) return 0;
  4. int a = 1;
  5. int b = 1;
  6. int temp = 1;
  7. for (int i = 0; i < n - 1; i++) {
  8. temp = a + b;
  9. a = b;
  10. b = temp;
  11. }
  12. return temp;
  13. }
  14. }

扩展:不能连续每次上两个台阶。爬楼梯 - 简单 - 图3,好好理解
image.png
看到图后,可能会有疑惑爬楼梯 - 简单 - 图5为什么不行。其实看你怎么理解爬楼梯 - 简单 - 图6这个函数吧,如果它表示输入爬楼梯 - 简单 - 图7求,输出能够爬到楼顶的方式的数量的话,那么爬楼梯 - 简单 - 图8很明显不对,因为爬楼梯 - 简单 - 图9第一步可以走两个台阶,而但是根据上图可以知道如果第一步走2个台阶,第2步只能走1个台阶,爬楼梯 - 简单 - 图10会把在该次函数中的第一步为2个阶梯的可能性也算上。看图,可以发现,右侧n-3结点可以走两个台阶;而且n结点到该n-3结点只有一条路,那么n结点右侧的所有道路,有n-3结点来决定,所以可以得到新的斐波那契数列。

递归法

超时:

  1. class Solution {
  2. public int climbStairs(int n) {
  3. if(n < 0) return 0;
  4. return climb(n);
  5. }
  6. public static int climb(int n){
  7. if(n == 0) return 1;
  8. if(n < 0) return 0;
  9. return climb(n - 1) + climb(n - 2);
  10. }
  11. }

image.png

枚举法:

1、每次走1阶
2、整个过程只有1次一次性走两个台阶
3、整个过程只有2次一次性走两个台阶
······
内存溢出:

  1. public class ClimbingStair {
  2. public int climbStairs(int n) {
  3. if (n < 1) return 0;
  4. int result = 1;
  5. List<Integer> list = new ArrayList<>();
  6. for (int i = 0; i < n-1; i++) {
  7. list.add(i);
  8. }
  9. for (int i = 0; i < n / 2; i++) {
  10. list = climb(list, n);
  11. result += list.size();
  12. }
  13. return result;
  14. }
  15. public static List<Integer> climb(List<Integer> list, int len) {
  16. List<Integer> nlist = new ArrayList<>();
  17. int e;
  18. for (Integer integer : list) {
  19. e = integer + 2;
  20. while (e+1 < len) {
  21. nlist.add(e);
  22. e += 2;
  23. }
  24. }
  25. return nlist;
  26. }
  27. }

image.png
某个阶梯多从重复,那么可以利用hashmap记录参数:

  1. class Solution {
  2. public int climbStairs(int n) {
  3. if (n < 1) return 0;
  4. int result = n;
  5. Map<Integer, Integer> map = new HashMap<>();
  6. for (int i = 0; i < n - 1; i++) {
  7. map.put(i, 1);
  8. }
  9. for (int i = 1; i < n / 2; i++) {
  10. map = climb(map, n);
  11. for (int k : map.keySet()){
  12. result += map.get(k);
  13. }
  14. }
  15. return result;
  16. }
  17. public static Map<Integer, Integer> climb(Map<Integer, Integer> map, int len) {
  18. Map<Integer, Integer> nmap = new HashMap<>();
  19. int e;
  20. for (Map.Entry<Integer,Integer> entry : map.entrySet()){
  21. e = entry.getKey() + 2;
  22. while (e + 1 < len) {
  23. nmap.put(e,nmap.getOrDefault(e,0)+entry.getValue());
  24. e += 1;
  25. }
  26. }
  27. return nmap;
  28. }
  29. }

image.png