【力扣 - 爬楼梯】

题目描述

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

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

方法一:动态规划

思路和算法

我们用 f(x) 表示爬到第 x 级台阶的方案数,考虑最后一步可能跨了一级台阶,也可能跨了两级台阶,所以我们可以列出如下式子:

c 复制代码
f(x)=f(x−1)+f(x−2)

它意味着爬到第 x 级台阶的方案数是爬到第 x−1 级台阶的方案数和爬到第 x−2 级台阶的方案数的和。很好理解,因为每次只能爬 1 级或 2 级,所以 f(x)只能从 f(x−1)f(x−2) 转移过来,而这里要统计方案总数,我们就需要对这两项的贡献求和。

以上是动态规划的转移方程,下面我们来讨论边界条件。我们是从第 0 级开始爬的,所以从第 0 级爬到第 0 级我们可以看作只有一种方案,即 f(0)=1;从第 0 级到第 1 级也只有一种方案,即爬一级,f(1)=1。这两个作为边界条件就可以继续向后推导出第 n 级的正确结果。我们不妨写几项来验证一下,根据转移方程得到 f(2)=2f(3)=3f(4)=5,......,我们把这些情况都枚举出来,发现计算的结果是正确的。

我们不难通过转移方程和边界条件给出一个时间复杂度和空间复杂度都是 O(n) 的实现,但是由于这里的 f(x) 只和 f(x−1)f(x−2) 有关,所以我们可以用「滚动数组思想」把空间复杂度优化成 O(1)





代码

c 复制代码
int climbStairs(int n) {
    // Initialize three variables to keep track of the number of ways to climb stairs
    int p = 0, q = 0, r = 1;
    
    // Loop from 1 to n to calculate the number of ways to climb n stairs
    for (int i = 1; i <= n; ++i) {
        // Update p to the previous value of q
        p = q;
        // Update q to the previous value of r
        q = r;
        // Update r to the sum of p and q, representing the total ways to climb i stairs
        r = p + q;
    }
    
    // Return the total number of ways to climb n stairs
    return r;
}

复杂度分析

  • 时间复杂度:循环执行 n 次,每次花费常数的时间代价,故渐进时间复杂度为 O(n)
  • 空间复杂度:这里只用了常数个变量作为辅助空间,故渐进空间复杂度为 O(1)

方法二:矩阵快速幂

思路

以上的方法适用于 n 比较小的情况,在 n 变大之后,O(n) 的时间复杂度会让这个算法看起来有些捉襟见肘。我们可以用「矩阵快速幂」的方法来优化这个过程。

代码

c 复制代码
// Define a struct to represent a 2x2 matrix
struct Matrix {
    long long mat[2][2];
};

// Function to multiply two matrices
struct Matrix multiply(struct Matrix a, struct Matrix b) {
    struct Matrix c;
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            // Calculate the elements of the resulting matrix by multiplying and summing
            c.mat[i][j] = a.mat[i][0] * b.mat[0][j] + a.mat[i][1] * b.mat[1][j];
        }
    }
    return c;
}

// Function to calculate the n-th power of a matrix using binary exponentiation
struct Matrix matrixPow(struct Matrix a, int n) {
    struct Matrix ret;
    // Initialize the result matrix with identity values
    ret.mat[0][0] = ret.mat[1][1] = 1;
    ret.mat[0][1] = ret.mat[1][0] = 0;

    while (n > 0) {
        if ((n & 1) == 1) {
            // If the current power is odd, multiply the result by the base matrix
            ret = multiply(ret, a);
        }
        n >>= 1; // Right shift to divide the power by 2
        a = multiply(a, a); // Square the base matrix
    }
    return ret;
}

// Function to calculate the number of ways to climb n stairs
int climbStairs(int n) {
    struct Matrix ret;
    // Initialize the matrix with specific values for the climbing stairs problem
    ret.mat[1][1] = 0;
    ret.mat[0][0] = ret.mat[0][1] = ret.mat[1][0] = 1;

    // Calculate the n-th power of the matrix to get the result
    struct Matrix res = matrixPow(ret, n);
    return res.mat[0][0]; // Return the number of ways to climb n stairs
}

复杂度分析

  • 时间复杂度:同快速幂,O(log ⁡n)
  • 空间复杂度:O(1)

方法三:通项公式

思路

代码

c 复制代码
// Function to calculate the number of ways to climb n stairs
int climbStairs(int n) {
    // Calculate the square root of 5
    double sqrt5 = sqrt(5);
    
    // Calculate the n-th Fibonacci number using Binet's formula
    double fibn = pow((1 + sqrt5) / 2, n + 1) - pow((1 - sqrt5) / 2, n + 1);
    
    // Divide the Fibonacci number by the square root of 5 and round it to the nearest integer
    return (int) round(fibn / sqrt5);
}

总结

相关推荐
Django强哥8 分钟前
JSON Schema Draft-07 详细解析
javascript·算法·代码规范
AndrewHZ9 分钟前
【图像处理基石】GIS图像处理入门:4个核心算法与Python实现(附完整代码)
图像处理·python·算法·计算机视觉·gis·cv·地理信息系统
杨小码不BUG37 分钟前
蛇形舞动:矩阵填充的艺术与算法(洛谷P5731)
c++·算法·矩阵·csp-j/s·循环控制
MicroTech20251 小时前
微算法科技(NASDAQ:MLGO)开发延迟和隐私感知卷积神经网络分布式推理,助力可靠人工智能系统技术
人工智能·科技·算法
Boop_wu2 小时前
[数据结构] Map和Set
java·数据结构·算法
思考的笛卡尔3 小时前
密码学基础:RSA与AES算法的实现与对比
网络·算法·密码学
格林威9 小时前
常规线扫描镜头有哪些类型?能做什么?
人工智能·深度学习·数码相机·算法·计算机视觉·视觉检测·工业镜头
程序员莫小特11 小时前
老题新解|大整数加法
数据结构·c++·算法
过往入尘土12 小时前
服务端与客户端的简单链接
人工智能·python·算法·pycharm·大模型
zycoder.12 小时前
力扣面试经典150题day1第一题(lc88),第二题(lc27)
算法·leetcode·面试