题目描述
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:1
示例 2:
输入:n = 5
输出:5
提示:
0 <= n <= 100
我的解法
class Solution {
public int fib(int n) {
if(n==0) return 0;
if(n==1) return 1;
return fib(n-1)+fib(n-2);//迭代法
}
}
结果:大量重复的递归计算,超出时间限制
官方解法
求余运算规则: 设正整数 x, y, p,求余符号为 ⊙ ,则有 (x+y)⊙p=(x⊙p+y⊙p)⊙p 。
解析: 根据以上规则,可推出 f(n)⊙p=[f(n−1)⊙p+f(n−2)⊙p]⊙p ,从而可以在循环过程中每次计算 sum=(a+b)⊙1000000007 ,此操作与最终返回前取余等价。
class Solution {
public int fib(int n) {
int a = 0, b = 1, sum;
for(int i = 0; i < n; i++){ //为了代码简洁,从0开始,不需要考虑n=0和1的情况
sum = (a + b) % 1000000007;
a = b; //但是必须返回a,因为是多算了1次的
b = sum;
}
return a;
}
}
解法优化
class Solution {
public int fib(int n) {
if (n <= 1) return n;
int first = 0;
int second = 1;
while (--n > 0) {
second = second+first;
//少定义一个变量,通过运算直接得出答案,但是求和后直接取余,再做减法运算可能会得到负数,
//所以要在做完减法运算后取余,不能在这里一步写完。
first = second-first;
if (second >= 1000000007) {
second -= 1000000007;
//因为只有可能是刚超出100000007,所以采用减去1000000007比取余更节约时间
}
}
return second;
}
}
剖析
考虑溢出与取余,细节全是戏~