1 题目
leetcode
写一个函数,输入n,求斐波那契数列的第n项。斐波那契书写的定义如下:
F(0)=0,F(1)=1
F(N)=F(N-1)+F(N-2),其中N>1
斐波那契数列由0和1开始,之后的斐波那契数列就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
2 解
2.1 超时解
public int fib(int n) {
return (int) (recursive(n)%(1e9+7));
}
public int recursive(int n){
if(n==0)
return 0;
if(n==1)
return 1;
return recursive(n-1)+recursive(n-2);
}
直接使用递归求解,当要求的数字较大时,结果会超出时间限制。
2.2 优化后的递归
直接使用递归求解超时是因为由很多重复的计算,可以引入一个Map存储已经算出的结果,提高运行效率。最终代码如下
public int fib(int n) {
Map<Integer,Integer> map=new HashMap<Integer, Integer>();
map.put(0, 0);
map.put(1, 1);
return (recursive(n,map));
}
public int recursive(int n, Map<Integer, Integer> map){
if(n==0)
return 0;
if(n==1)
return 1;
//是否有 n-1的值
if (!map.containsKey(n-1)) {
//计算并放入
map.put(n-1, recursive(n-1, map));
}
if (!map.containsKey(n-2)) {
//计算并放入
map.put(n-2, recursive(n-2, map));
}
return (map.get(n-1)+map.get(n-2))%(1000000007);
}
2.2.1 求解遇到的错误
在优化的过程中遇到了一些错误,记录一下。
首先是测试用例27,输入48,预期值与输出值差距过大,调试发现是值越界导致变成了负数,所以改成了long型存储。
然后是测试用例41,输入81,预期值与输出值仅差2,百度发现取模时应该写成数字1000000007,修改后通过。
然后是测试用例47,输入95,输出值变成负数了,毫无疑问是越界了。long型也无法存储的话,只能在存储进map之前就进行取模了,修改后通过。
最后尝试着将所有数据都使用int型存储,也通过了。
3 其它解
3.1 循环求解
利用循环自底向上求解,可以防止重复计算。
public int fib(int n) {
int a=0,b=1,sum;
for (int i = 0; i < n; i++) {
sum=(a+b)%(1000000007);
a=b;
b=sum;
}
return a;
}
4 参考链接
1.如何以1e9+7取模?
2.精选解
2020.09.07更新
新的递归代码,从青蛙跳台阶的一个解中看到的,青蛙跳台阶和斐波那契数列区别在于起始值的不同,解法类似。
public int fib(int n) {
Map<Integer,Integer> map=new HashMap<Integer, Integer>();
map.put(0, 0);
map.put(1, 1);
return (recursive(n,map));
}
public int recursive(int n, Map<Integer, Integer> map){
if(map.containsKey(n)) {
return map.get(n);
}else {
map.put(n, (recursive(n-1, map)+recursive(n-2, map))%(1000000007));
return map.get(n);
}
}
参考链接:递归法优化