一、题目
写一个函数,输入 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.递归
class Solution:
#递归
#1.确定递归函数参数和返回值
def fib(self, n: int) -> int:
#2.确定递归函数的终止条件
if n==0:
return 0
if n==1:
return 1
#3.确定单层递归的逻辑
return self.fib(n-1)+self.fib(n-2)
出现问题:
(1)递归深度过大的话,容易导致栈溢出
(2)会进行大量重复操作
F(5)=F(4)+F(3)
F(4)=F(3)+F(2)
F(3)=F(2)+F(1)
F(2)=F(1)+F(0)
F(3)=F(2)+F(1)
2.动态规划
1.动态规划解析:
- 状态定义: 设 dp为一维数组,其中 dp[i]的值代表 斐波那契数列第 i 个数字 。
- 转移方程: dp[i + 1] = dp[i] + dp[i - 1],即对应数列定义 f(n + 1) = f(n) + f(n - 1) ;
- 初始状态: dp[0] = 0, dp[1] = 1 ,即初始化前两个数字;
- 返回值: dp[n] ,即斐波那契数列的第 n个数字。
2.动态规划五部曲:
公众号:代码随想录
https://mp.weixin.qq.com/s/ko0zLJplF7n_4TysnPOa_w
1.确定dp数组(dp table)以及下标的含义
dp[i]的定义为:第i个数的斐波那契数值是dp[i]
#下标表示第i项的值,从第0项开始 ---> 第n项, 共n+1项
dp=[0]*(n+1)
2.确定递归公式
dp[n]=dp[n-1]+dp[n-2]
-
dp数组如何初始化
dp[0]=0 dp[1]=1
-
确定遍历顺序
#从前向后遍历 #从i=2,到i=n
-
举例推导dp数组
dp[2]=dp[1]+dp[0]
dp[3]=dp[2]+dp[1]
#打印dp数组
N=10,dp: 0 1 1 2 3 5 8 13 21 34 55
#将状态转移在dp数组上模拟
使用数组存储已经计算的结果,避免重复计算。
class Solution:
def fib(self, n: int) -> int:
# 1.动态规划
#当n=0和1时,n-1为-1和0
if n==0 or n==1:
return n
dp=[0]*(n+1)
dp[0]=0
dp[1]=1
# fib数列下标从0开始,需要得到第n个项
#数组下标也是从0开始,第n项为dp[n]
for i in range(2,n+1):
dp[i]=dp[i-1]+dp[i-2]
return dp[n]%1000000007
时间复杂度:O(n)
空间复杂度:O(n)
维护两个数值就可以了,不需要记录整个序列。
class Solution:
def fib(self, n: int) -> int:
#动规是由前一个状态推导出来的
if n==0 or n==1:
return n
dp=[0]*2
dp[0]=0
dp[1]=1
for i in range(2,n+1):
sum=dp[0]+dp[1]
dp[0]=dp[1]
dp[1]=sum
return sum
时间复杂度:O(n)
空间复杂度:O(1)
class Solution:
def fib(self, n: int) -> int:
# 1.动态规划
a,b=0,1
sum=0
#当n=0和1时,n-1为-1和0
if n==0 or n==1:
return n
#for循环运行第一次时,sum值为第3项值,a为第二项值,b为第三项
#如果n=2,只需要输出一次,n=3,需要输出2次
for _ in range(n-1):
sum=a+b
a=b
b=sum
return b%1000000007
class Solution:
def fib(self, n: int) -> int:
# 1.动态规划
a,b=0,1
sum=0
for _ in range(n):
sum=a+b
a=b
b=sum
return a%1000000007
Python中 整型数字的大小 取决于计算机的内存(可理解为无限大)。不考虑整数越界问题。