如何用O(logN)的时间算出爬楼梯?

332 阅读2分钟

爬楼梯是一道经典的算法题,也是递归和动态规划入门必会的一道题目。

leetcode70.爬楼梯

简单地说,就是求出斐波那契数列f(n) = f(n-1) + f(n-2)的第N项,即为本题的解。递归方法和动态规划方法的时间复杂度分别是O(2^N)和O(N),这里不再赘述。那你知道如何用O(logN)的时间复杂度解出爬楼梯问题吗?

在此之前我们先来讨论一下,计算X^N的时间复杂度是多少呢?我们可以for循环N次求出结果值,这样做的时间复杂度是O(N),也可以先算出X^1,做平方得出X^2,再依次做平方得出X^4、X^8,直到得出X^N的结果,因此我们可以在O(logN)的时间内计算出X^N。这个结论无论N是否是2的整数次方都是适用的。

如果对这里有疑问的话,可以去看一下leetcode 50题的题解

leetcode50.Pow(x, n)

    /**
     * 作者:力扣官方题解
     * 链接:https://leetcode.cn/problems/powx-n/
     * 来源:力扣(LeetCode)
     * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
     */
    public double quickMul(double x, long N) {
        double ans = 1.0;
        // 贡献的初始值为 x
        double x_contribute = x;
        // 在对 N 进行二进制拆分的同时计算答案
        while (N > 0) {
            if (N % 2 == 1) {
                // 如果 N 二进制表示的最低位为 1,那么需要计入贡献
                ans *= x_contribute;
            }
            // 将贡献不断地平方
            x_contribute *= x_contribute;
            // 舍弃 N 二进制表示的最低位,这样我们每次只要判断最低位即可
            N /= 2;
        }
        return ans;
    }

回过头来观察这个递推公式 f(n) = f(n-1) + f(n-2),如果我们把[f(n1)f(n)]\left[\begin{matrix}f(n-1)&f(n)\end{matrix}\right]看成是一个1 * 2的矩阵,那么

[f(n1)f(n)]=[f(n2)f(n1)]×[0111]\left[\begin{matrix}f(n-1)&f(n)\end{matrix}\right] = \left[\begin{matrix}f(n-2)&f(n-1)\end{matrix}\right] \times \left[\begin{matrix}0&1\\1&1\end{matrix}\right]

这样就可以推导出

[f(2)f(3)]=[f(1)f(2)]×[0111]\left[\begin{matrix}f(2)&f(3)\end{matrix}\right] = \left[\begin{matrix}f(1)&f(2)\end{matrix}\right] \times \left[\begin{matrix}0&1\\1&1\end{matrix}\right]
[f(3)f(4)]=[f(2)f(3)]×[0111]=[f(1)f(2)]×[0111]2\left[\begin{matrix}f(3)&f(4)\end{matrix}\right] = \left[\begin{matrix}f(2)&f(3)\end{matrix}\right] \times \left[\begin{matrix}0&1\\1&1\end{matrix}\right] = \left[\begin{matrix}f(1)&f(2)\end{matrix}\right] \times \left[\begin{matrix}0&1\\1&1\end{matrix}\right] ^ 2

所以我们就可以得出下面的公式

[f(n1)f(n)]=[f(1)f(2)]×[0111]n2\left[\begin{matrix}f(n-1)&f(n)\end{matrix}\right] = \left[\begin{matrix}f(1)&f(2)\end{matrix}\right] \times \left[\begin{matrix}0&1\\1&1\end{matrix}\right] ^{n-2}

按照我们前面的推导,计算X的N次方时间复杂度是O(logN),这个结论对于求矩阵的N的次方也同样适用,所以求出矩阵[f(n1)f(n)]\left[\begin{matrix}f(n-1)&f(n)\end{matrix}\right]的时间复杂度也就是O(logN),那么求出f(N)的时间复杂度就也是O(logN)了