爬楼梯

一、问题描述

有一座高度是 10 级台阶的楼梯,从下往上走,每跨一步只能向上 1 级或者 2 级台阶。要求用程序来求出一共有多少种走法。

二、算法分析

从简单的分析,要到第 10 级台阶,有多少种方法?要么从 9 级跨 1 级,要么从 8 级跨 1 级。

记 10 级台阶的状态为 f(10),9 级台阶的状态为 f(9),8 级台阶的状态为 f(8),那么 f(10) = f(9) + f(8)。

f(9) = f(8) + f(7)

...

f(2) = 2

f(1) = 1

f(8)、f(9) 是 f(10) 的【最优子结构】;f(1)、f(2) 是【边界】;f(n) = f(n-1) + f(n-2) 是【状态转移方程】。

三、代码实现

①、递归

int getClimbingWays(int n)
{
    if (n < 3) return n;
    
    return getClimbingWays(n - 1) + getClimbingWays(n - 2);
}

递归调用的执行过程和一颗二叉树一样,所以它的时间复杂度就是叶子节点数。

时间复杂度:O(2n)

②、备忘录算法

递归方法中会重复计算相同的值,如图中的 f(n-3)。用缓存,先创建一个哈希表,每次把不同参数的计算结果存入哈希。当遇到相同参数时,再从哈希表里去除,避免重复计算。

#include <stdio.h>
#include <stdlib.h>

int getClimbingWays(int n, int* hashMap)
{
    if (n < 3) return n;
    
    // 没有缓存
    if (hashMap[n] == 0) {
        int value = getClimbingWays(n - 1, hashMap) + getClimbingWays(n - 2, hashMap);
        hashMap[n] = value;
    }
    return hashMap[n];
}

int main()
{
    int n = 10;
    int* hashMap = (int *)calloc(n, sizeof(int));
    
    printf("%d", getClimbingWays(n, hashMap));
    
    return 0;
}

时间复杂度:O(n)

空间复杂度:O(n)

③、动态规划法

int getClimbingWays(int n)
{
    if (n < 3) return n;
    
    int a = 1;
    int b = 2;
    int sum = 0;
    
    for (int i = 3; i <= n; i++) {
        sum = a + b;
        a = b;
        b = sum;
    }
    
    return sum;
}

时间复杂度:O(n)

空间复杂度:O(1)

四、内容来源

漫画:什么是动态规划?

原文地址:https://www.cnblogs.com/dins/p/climb-stairs.html