问题描述
有个小孩正在上楼梯,楼梯有n阶台阶,小孩一次可以上1阶、2阶、3阶。 请实现一个方法,计算小孩有多少种上楼的方式。
为了防止溢出,请将结果Mod 1000000007
给定一个正整数int n,请返回一个数,代表上楼的方式数。
保证n小于等于100000。
问题分析
假设n阶台阶有f(n)种走法
当n = 1时,明显只有f(1) = 1种走法。
当n = 2时,假如第一步走1阶,那么问题就变成剩下1阶台阶有多少种走法,有f(1)种;假设第一步走2阶,那么只有1种走法,所以当n = 2时一共有f(2) = f(1) + 1 = 2种走法。
当n = 3时,假如第一步走1阶,那么问题就变成剩下2阶台阶有多少种走法,有f(2)种;假如第一步走2阶,那么问题就变成剩下1阶台阶有多少种走法,有f(1)种;假如第一步走3阶,那么只有1种走法,所以一共有f(3) = f(2) + f(1) + 1 = 4种走法。
…
同理,n阶楼梯时,假如第一步走1阶,那么问题就变成剩下(n - 1)阶台阶有多少种走法,有f(n - 1)种;假如第一步走2阶,那么问题就变成剩下(n - 2)阶台阶有多少种走法,有f(n - 2)种;假如第一步走3阶,那么只有f(n - 3)种走法,所以一共有f(n) = f(n - 1) + f(n - 2) + f(n - 3)种走法。
n | f(n) |
---|---|
1 | 1 |
2 | 2 |
3 | 4 |
4 | 7 |
5 | 13 |
… | … |
n | f(n - 1) + f(n - 2) + f(n - 3) |
代码实现
显然,这也是一种斐波那契数列
1.递归法
public class FibonacciStep {
public static void main(String[] args) {
int n = 10;
System.out.println(Fibonacci(n));
}
private static int Fibonacci(int n) {
if (n < 0) {
return 0;
}
if (n == 0 || n == 1) {
return 1;
}
if (n == 2) {
return 2;
}
return Fibonacci(n - 1) % 1000000007 + Fibonacci(n - 2) % 1000000007 + Fibonacci(n - 3) % 1000000007;
}
}
递归法虽然看起来更好理解,但是其时间复杂度和空间复杂度极高,当处理很大的数据时,运行效率很低,甚至栈内存溢出。
2.迭代法
public class FibonacciStep {
public static void main(String[] args) {
int n = 100000;
System.out.println(Fibonacci(n));
}
private static int Fibonacci(int n) {
if (n < 0) return 0;
if (n == 0 || n == 1) return 1;
if (n == 2) return 2;
if (n == 3) return 4;
int f1 = 1;
int f2 = 2;
int f3 = 4;
for (int i = 4; i <= n; i++) {
int temp = (f1 + f2 + f3) % 1000000007;
f1 = f2 % 1000000007;
f2 = f3 % 1000000007;
f3 = temp;
}
return f3;
}
}