斐波那契数列的三种解法

写一个函数,输入n,求斐波那契数列的第n项。

斐波那契数列的定义如下

 

一、效率极低的解法(递归)

课本的上为了讲解递归算法,经常用这个例子。让我们看一下它的实现

  1. package algorithm;
  2. public class Fibonacci_recursion {
  3.     // 1 1 2 3 5 8 13 21 34 55
  4.     long Fibonacci(int n) {
  5.         if(n<=0return 0;
  6.         if(n==1return 1;
  7.         if(n==2return 1;
  8.         if(n>2return Fibonacci(n-1)+Fibonacci(n-2);
  9.         return 0;
  10.     }
  11.     public static void main(String args[]) {
  12.         Fibonacci_recursion f = new Fibonacci_recursion();
  13.         long startTime = System.currentTimeMillis();
  14.         long x = f.Fibonacci(40);
  15.         long endTime = System.currentTimeMillis();
  16.         System.out.println("程序运行时间:"+(endTime-startTime)+"ms");//534
  17.         System.out.println(x);
  18.     }
  19. }

因为随着 n 的大小变化,返回值会越来越大,防止越界,这里使用 long 而不是 int 类型。

我们知道,递归算法的执行时间是随着 n 的大小变化而成指数递增。

博主在自己的机器上测试。求 4 的斐波那契项,用时可能可以忽略, 0 ms;求 40 的斐波那契项 用时 534 ms; 然后 求 50 呢,机器的风扇开始响了,几十秒过去了,都没结果。

可见,使用递归求斐波那契数列项,容易理解,但是效率真的很 bad 。

因为,当我们求 Fibonacci(10) 的时候,要求 Fibonacci(9) 和 Fibonacci(8); 同样,求 Fibonacci(9) 的时候要先求 Fibonacci(8) 和 Fibonacci(7)... 这下面会有很多重复计算的过程。比如几乎计算所有的项都算了 Fibonacci(1)+Fibonacci(2)。

如果我们把这个用树形结构来表示,可以看做一个根节点在上的自上而下的二叉树,每次计算都会重复计算很多子节点。

 

二、线性解法,时间复杂度 O(n)

如果我们不使用递归算法,而是使用常规的解法,效果是不是会高很多呢?至少要把时间复杂度给降下来吧。

常规解法怎么做呢?

如果是求 Fibonacci(10),我们先把 求 Fibonacci(1), Fibonacci(2),然后根据前两者求 Fibonacci(3),然后再 求 Fibonacci(4),一直求到 Fibonacci(10) 。

这其实只需要一个 for 循环,所有,时间复杂度为 O(n)。

代码实现

  1. package algorithm;
  2. public class Fibonacci_linear {
  3.     // 1 1 2 3 5 8 13 21 34 55
  4.     long Fibonacci(int n) {
  5.         long num1 = 0, num2=1, temp=0;
  6.         for(int i=1;i<n;i++) {
  7.             temp = num1+num2;
  8.             num1 = num2;
  9.             num2 = temp;
  10.         }
  11.         return num2;
  12.     }
  13.     public static void main(String args[]) {
  14.         Fibonacci_linear f = new Fibonacci_linear();
  15.         long startTime = System.currentTimeMillis();
  16.         long x = f.Fibonacci(4000000);
  17.         long endTime = System.currentTimeMillis();
  18.         System.out.println("程序运行时间:"+(endTime-startTime)+"ms");//0
  19.         System.out.println(x);
  20.     }
  21. }

由于时间复杂度为 O(n) ,也就是说,随着 n 的变大我们的时间都是可以忽略的,无论是 Fibonacci(40) ,Fibonacci(400) ,Fibonacci(4000),Fibonacci(4000000) 都是可以计算且时间都很短的。

比如求 Fibonacci(4000000) 最终结果如下

程序运行时间:5ms

6558868233897966651

可见该方法比第一种的递归好多少,这也应该是面试官所青睐的。

 

三、时间复杂度 O(logn) 但不实用的算法

待补充...





本文地址:https://liuyanzhao.com/6380.html

### 回答1: 这是一个经典的斐波那契数列问题。由于 n 的范围很大,所以直接递归或者暴力计算是不可行的,需要使用动态规划或矩阵快速幂的方法来求解。 方法一:动态规划 可以使用一个长度为 n+1 的一维数组 dp 来存储斐波那契数列中前 n 项的值,其中 dp[i] 表示第 i 项的值。根据斐波那契数列的递推公式,可以得到状态转移方程:dp[i] = (dp[i-1] + dp[i-2]) % 998244353。 最终 dp[n] 就是该数列的第 n 项了。 下面是 Python 代码实现: ```python def fibonacci(n): mod = 998244353 dp = [0] * (n + 1) dp[1] = dp[2] = 1 for i in range(3, n+1): dp[i] = (dp[i-1] + dp[i-2]) % mod return dp[n] ``` 方法二:矩阵快速幂 斐波那契数列也可以用矩阵快速幂的方式来求解。首先,将斐波那契数列的递推公式转化成矩阵形式: ``` | F(n) | | 1 1 | | F(n-1) | | | = | | * | | | F(n-1) | | 1 0 | | F(n-2) | ``` 然后,对于求解第 n 项的问题,我们只需要计算矩阵 A = [1 1; 1 0] 的 n-1 次方,即可得到结果。具体地,可以使用矩阵快速幂的方法来计算。 下面是 Python 代码实现: ```python def fibonacci(n): mod = 998244353 def matrix_multiply(a, b): c = [[0, 0], [0, 0]] for i in range(2): for j in range(2): for k in range(2): c[i][j] += a[i][k] * b[k][j] c[i][j] %= mod return c def matrix_power(a, n): res = [[1, 0], [0, 1]] while n > 0: if n % 2 == 1: res = matrix_multiply(res, a) a = matrix_multiply(a, a) n //= 2 return res a = [[1, 1], [1, 0]] res = matrix_power(a, n-1) return res[0][0] ``` 以上两种方法都可以求解斐波那契数列的第 n 项,时间复杂度均为 O(n) 或 O(log n)。 ### 回答2: 斐波那契数列是由两个初始项1开始,每一项都是前两项的和。为了求解数列的第n项,可以使用递归或循环的方法。 使用递归的方法,可以定义一个递归函数fibonacci(n),该函数的参数为n,表示要求解的第n项。如果n小于等于2,则直接返回1;否则,返回fibonacci(n-1)加上fibonacci(n-2)的模998244353的结果。 示例如下: ```python def fibonacci(n): if n <= 2: return 1 else: return (fibonacci(n-1) + fibonacci(n-2)) % 998244353 ``` 如果使用循环的方法,可以通过初始化前两项为1,然后从第3项开始循环求解。定义变量a和b分别表示当前项和前一项的值,并用一个循环从3到n迭代更新a和b的值。每次更新都使a的值变为a与b的和模998244353,同时b的值变为原来的a值。循环结束后,返回a的值即为第n项。 示例如下: ```python def fibonacci(n): if n <= 2: return 1 else: a, b = 1, 1 for i in range(3, n+1): a, b = (a + b) % 998244353, a return a ``` 以上是用Python编写的求解斐波那契数列第n项的方法。当然,也可以使用其他编程语言来实现相同的逻辑。 ### 回答3: 斐波那契数列是一种特殊的数列,每一项都是前两项的和。已知 F n ​ =F n−1 ​ +F n−2 ​ ,其中 n>=3,F 1 ​ =1,F 2 ​ =1。 为了求解数列的第n项,并且结果对998244353取模,我们可以使用动态规划的方法。 首先,我们可以定义一个数组 dp,dp[i] 表示第i项的斐波那契数值。 然后,我们可以通过迭代的方式计算每一项的斐波那契数值。具体步骤如下: 1. 初始化数组 dp,将前两项 F 1 和 F 2 的值赋给 dp[1] 和 dp[2]; 2. 使用循环从3开始遍历,计算每一项的斐波那契数值,即 dp[i] = dp[i-1] + dp[i-2]; 3. 循环结束后,dp[n] 中存储的即为第 n 项的斐波那契数值。 最后,我们将 dp[n] 对 998244353 取模,得到的结果即为第 n 项的斐波那契数对 998244353 取模的值。 以上就是求解斐波那契数列第n项,并对998244353取模的方法。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半缘修道半缘君丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值