Leetcode70. Climbing Stairs

Leetcode70. Climbing Stairs

You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.

Example 1:

Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps

Example 2:

Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
解法一:暴力法

要求 n 层的台阶的走法,由于一次走 1 或 2 个台阶,所以上到第 n 个台阶之前,一定是停留在第 n - 1 个台阶上,或者 n - 2 个台阶上。所以如果用 f ( n ) 代表 n 个台阶的走法。那么f(n) = f(n - 1) + f(n - 2)f(1) = 1f(2) = 2 。发现个神奇的事情,这就是斐波那契数列(Fibonacci sequence)。

public int climbStairs(int n) {
    return climbStairsN(n);
}

private int climbStairsN(int n) {
    if (n == 1) {
        return 1;
    }
    if (n == 2) {
        return 2;
    }
    return climbStairsN(n - 1) + climbStairsN(n - 2);
}

  • 时间复杂度: O ( 2 n ) O(2^n) O(2n)
  • 空间复杂度: O ( n ) O(n) O(n)
解法二:记忆化递归

在上一种方法中,我们计算每一步的结果时出现了冗余。另一种思路是,我们可以把每一步的结果存储在memo数组中,每当函数再次被调用,我们就直接从 memo数组中返回结果。这样我们得到一颗修复的递归树。

public int climbStairs(int n) {
        int memo[] = new int[n + 1];
        return climb_Stairs(0, n, memo);
    }
    public int climb_Stairs(int i, int n, int memo[]) {
        if (i > n) {
            return 0;
        }
        if (i == n) {
            return 1;
        }
        if (memo[i] > 0) {
            return memo[i];
        }
        memo[i] = climb_Stairs(i + 1, n, memo) + climb_Stairs(i + 2, n, memo);
        return memo[i];
    }
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)
解法三:动态规划

dp[i]是可以达到第i阶的方法总数,则dp[i] = dp[i-1]+dp[i-2]

public class Solution {
    public int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }
        int[] dp = new int[n + 1];
        dp[1] = 1;
        dp[2] = 2;
        for (int i = 3; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

思考状态压缩,因为每次只需要用到dp[i-1]与dp[i-1]两个数,因此可以用常数替换数组。

public class Solution {
    public int climbStairs(int n) {
        if (n == 1) {
            return 1;
        }
        int first = 1;
        int second = 2;
        for (int i = 3; i <= n; i++) {
            int third = first + second;
            first = second;
            second = third;
        }
        return second;
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
解法四:矩阵相乘

定义一个矩阵 Q = [ 1 1 1 0 ] Q=\begin{bmatrix} 1 &1 \\ 1 & 0 \end{bmatrix} Q=[1110],要求f(n)的话,我们先让 Q 矩阵求幂,然后取第一行第一列的元素,也就是 f ( n ) = Q n [ 0 ] [ 0 ] f(n)=Q^n[0][0] f(n)=Qn[0][0]

public int climbStairs(int n) {
    int[][] Q = {{1, 1}, {1, 0}};
    int[][] res = pow(Q, n);
    return res[0][0];
}
public int[][] pow(int[][] a, int n) {
    int[][] ret = {{1, 0}, {0, 1}};
    while (n > 0) {
        //最后一位是 1,加到累乘结果里
        if ((n & 1) == 1) {
            ret = multiply(ret, a);
        }
        //n 右移一位
        n >>= 1;
        //更新 a
        a = multiply(a, a);
    }
    return ret;
}
public int[][] multiply(int[][] a, int[][] b) {
    int[][] c = new int[2][2];
    for (int i = 0; i < 2; i++) {
        for (int j = 0; j < 2; j++) {
            c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j];
        }
    }
    return c;
}
  • 时间复杂度: O ( l o g n ) O(logn) O(logn)(求幂)
  • 空间复杂度: O ( 1 ) O(1) O(1)

更快的求幂:解法三

解法五:公式法

在这里插入图片描述

public int climbStairs(int n) {
    double sqrt5=Math.sqrt(5);
    double fibn=Math.pow((1+sqrt5)/2,n+1)-Math.pow((1-sqrt5)/2,n+1);
    return (int)(fibn/sqrt5);
}
  • 时间复杂度: O ( l o g n ) O(logn) O(logn)(求幂)
  • 空间复杂度: O ( 1 ) O(1) O(1)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值