一.题目描述
写一个函数,输入 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。
(0 <= n <= 100)
二.解题思路
1.递归
public int fib1(int n) {
if(n == 0){
return 0;
}
if(n == 1){
return 1;
}
return (fib1(n-1) + fib1(n-2)) % 1000000007;
}
这种方法存在大量重复计算,时间复杂度随着N呈现指数增长
2.记忆化递归(去除重复计算)
public class Solution {
private int[] memo;
public int fib(int n) {
memo = new int[n+1];
Arrays.fill(memo,-1);
return fibmemo(n);
}
private int fibmemo(int n) {
if(memo[n] != -1){
return memo[n];
}
if(n == 0 || n == 1){
return n;
}
memo[n] = (fibmemo(n-1)+fibmemo(n-2)) % 1000000007;
return memo[n];
}
}
这种方法时间复杂度O(n),空间复杂度O(n)
3.数组记录斐波那契数列的值
public int fib(int n) {
if(n == 0) return 0;
int[] dp = new int[n + 1];
dp[1] = 1;
for(int i = 2; i < n + 1; i++){
dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007;
}
return dp[n];
}
时间复杂度O(n),空间复杂度O(n)
4.由于每次计算只需要知道前两项,所以只需要一个大小为2的数组,每次计算后更新数组,下次计算只需要用到近两次计算的结果即可
public int fib(int n) {
int[] arr = {0,1};
if(n < 0){
return -1;
}
if(n < 2){
return arr[n];
}
int temp;
for (int i = 1; i < n; i++) {
temp = (arr[0] + arr[1]) % 1000000007;
arr[0] = arr[1];
arr[1] = temp;
}
return arr[1];
}
这种方法时间复杂度O(n),空间复杂度O(1)
三.青蛙跳台阶问题
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
当n=1,只有1种跳法;
当n=2,有两种跳法,
当n=N,可以由N-1级,跳1步到N级;也可以由N-2步,跳2步到N级;所以总共跳法是二者之和。
这就是斐波那契数列的变形。
本题可转化为 求斐波那契数列第 n项的值 ,与 斐波那契数列 等价,唯一的不同在于起始数字不同。
代码如下:
初始f(1)=1,f(2)=2
public class Solution3 {
public int numWays(int n) {
int[] arr = {1,2};
if(n == 0){
return 1;
}
if(n < 3){
return arr[n - 1];
}
for (int i = 3; i < n + 1; i++) {
int temp = (arr[1] + arr[0]) % 1000000007;
arr[0] = arr[1];
arr[1] = temp;
}
return arr[1];
}
}