面试题 08.01. 三步问题

三步问题。有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶或3阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模1000000007。

示例1:

输入:n = 3 输出:4 说明: 有四种走法 示例2:

输入:n = 5 输出:13 提示:

n范围在[1, 1000000]之间

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/three-steps-problem-lcci 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解:
思路一:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 思路一:
// 递归
// 同斐波那契数列,递归解法存在大量重复的计算
// 递归解法,提交后,毫无疑问的超出时间限制
// 时间复杂度为指数级
public int waysToStep(int n) {
    if (n <= 2) return n;
    if (n == 3) return 4;

    return ((waysToStep(n - 1) + waysToStep(n - 2)) % 1000000007 + waysToStep(n - 3)) % 1000000007;
}
思路二:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 思路二
// 动态规划 递推
// 用dp数组记录,前n - 1阶,需要的步数
// 第 n 阶,需要的步数就是 dp数组中 n - 1, n - 2, n - 3 的和
// 时间复杂度 : O(N)
// 空间复杂度 : O(N),因为使用了dp数组存储之前结果
public int waysToStep1(int n) {
    if (n <= 2) return n;
    if (n == 3) return 4;

    int[] dp = new int[n];
    dp[0] = 1;
    dp[1] = 2;
    dp[2] = 4;

    for (int i = 3; i < n; i++) {
        dp[i] = ((dp[i - 1] + dp[i - 2]) % 1000000007 + dp[i - 3]) % 1000000007;
    }

    return dp[n - 1];
}
思路三:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 思路二
// 动态规划 递推
// 上个解法看出,貌似不需要使用数组记录之前结果
// 因为计算的当前结果,用到的知识前三个结果
// 下边我们尝试使用三个变量记录,优化空间复杂度
// 时间复杂度 : O(N)
// 空间复杂度 : O(1)
public int waysToStep2(int n) {
    if (n <= 2) return n;
    if (n == 3) return 4;

    int a = 1, b = 2, c = 4, result = 0;
    for (int i = 3; i < n; i++) {
        result = ((a + b) % 1000000007 + c) % 1000000007;

        a = b;
        b = c;
        c = result;
    }

    return result;
}