一、问题描述
有一座高度是 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)