用快速幂计算爬楼梯

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情

题目描述

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

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

image.png

image.png

思路分析

爬楼梯的算法有很多种,从最初学到的递归,以及通过两个变量不断存储pre值(这个思路有一点动态规划的影子,隐藏了一个状态转移的方程,不过不需要申请额外的O(n)级别的内存空间)。

然而递归的需要搞过深的栈,动态规划时间复杂度也是O(n) 可不可以进一步的减少时间复杂度呢?

看如下公式

[ 1 1 1 0 ] [ f ( n ) f ( n 1 ) ] = [ f ( n 1 ) + f ( n ) f ( n ) ] = [ f ( n + 1 ) f ( n ) ] \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix} \begin{bmatrix} f(n) \\ f(n - 1) \end{bmatrix} = \begin{bmatrix} f(n - 1) + f(n) \\ f(n) \end{bmatrix} = \begin{bmatrix} f(n + 1) \\ f(n) \end{bmatrix}

由此可得

[ 1 1 1 0 ] n [ f ( 1 ) f ( 0 ) ] = [ f ( n + 1 ) f ( n ) ] \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^n \begin{bmatrix} f(1) \\ f(0) \end{bmatrix} = \begin{bmatrix} f(n + 1) \\ f(n) \end{bmatrix}

那么这个问题的时间复杂度就简化成为求解

[ 1 1 1 0 ] n \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^n

的时间复杂度

这个n次幂的求解我们可以使用快速幂就行。将O(n)的时间复杂度变为O( l o g 2 n log_2n )

代码实现

 public int[][] pow(int[][] a, int n) {
        int[][] ret = {{1, 0}, {0, 1}};
        while (n > 0) {
            if ((n & 1) == 1) {
                ret = multiply(ret, a);
            }
            n >>= 1;
            a = multiply(a, a);
        }
        return ret;
    }
复制代码

总结

其实个人觉得爬楼梯使用动态规划就已经足够了,但偶尔确实会遇到一些追求时间复杂度的人或比赛要求使用快速幂作答。

快速幂的难点其实不在于其本身的实现,而是在于如何将一个问题抽象成可以使用快速幂求解的问题。

おすすめ

転載: juejin.im/post/7084231510508699685