(1)一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级。求该青蛙跳上一个n 级的台阶总共有多少种跳法。
(2)一只青蛙一次可以跳上1级台阶,也可以跳上2 级……它也可以跳上n 级,此时该青蛙跳上一个n级的台阶总共有多少种跳法?
分析:1)当n = 1, 只有1中跳法;当n = 2时,有两种跳法;当n = 3 时,有3种跳法;当n = 4时,有5种跳法;当n = 5时,有8种跳法;.......
规律类似于Fibonacci数列
解题思路:
思路一:递归法
把f(n)问题拆分成f(n-1)和f(n-2)子问题,缺点:大量重复计算。
int Fib(int n) {
if (n<=2)
{
return n;
}
else
{
return Fib(n - 1) + Fib(n - 2);
}
}
思路二:记忆化递归法
在递归法的基础上,新建一个长度为n的数组,用于存储f(0)至f(n)的数值,重复时直接在数组取用,避免了重复的递归计算,缺点:需要使用O(N)的额外空间。
思路三:动态规划算法(最佳解法)
以斐波那契数列性质f(n + 1) = f(n) + f(n - 1)为转移方程。
int numWays(int n) {
if (n<=1)
{
return 1;
}
int a = 1;
int b = 1;
int c = 0;
for (int i = 2; i <=n; i++)
{
c = (a + b) % 1000000007;
a = b;
b = c;
}
return c;
}
时间复杂度:O(N)
空间复杂度 :O(1)
为什么要对1000000007取模?
因为1000000007是一个质数(素数),对质数取余能最大程度避免冲突
int32位的最大值为2147483647,所以对于int32位来说1000000007足够大
int64位的最大值为2^63-1,对于1000000007来说它的平方不会在int64中溢出
取模前 f(43) = 701408733, f(44) = 1134903170, f(45) = 1836311903, 但是 f(46) > 2147483647结果就溢出了。
取模后 f(43) = 701408733, f(44) = 134903163 , f(45) = 836311896, f(46) = 971215059没有溢出。取模之后能够计算更多的情况,如 f(46)。这道题的测试答案与取模后的结果一致。
总而言之,模1000000007是通用做法,大数情况是为了防止溢出。