剑指 Offer 10- I. 斐波那契数列 - leetcode 剑指offer系列

题目难度: 简单

原题链接

今天继续更新剑指 offer 系列, 这道题实在太经典了, 它也是动态规划的基础题目, 估计大家都见过, 今天就来复习一下吧~ 另外下面的做法还会有一些空间上的优化, 值得关注

若无意外, 每天晚上 6 点 45 分准时更新, 中间可能会穿插一些周赛题解. 大家在我的公众号"每日精选算法题"中的聊天框中回复 offer 就能看到该系列当前已经更新的文章了

大家有什么想法建议和反馈的话欢迎随时交流, 包括但不限于公众号聊天框/知乎私信评论等等~

题目描述

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 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

输入

n = 2

输出

1

示例 2

输入

n = 5

输出

5

题目思考

  1. 如何利用递推条件?

解决方案

思路

分析

  • 初始化条件和递推式(转移方程)都给了, 这就是最基础的动态规划思想了: 保存已有信息, 新的信息通过已有信息计算得到(就是转移过程), 避免重复计算
  • 这里引申一点, 动态规划的难点在于如何将具体问题进行转换, 以及如何找到转移方程
  • 我的建议是遇到问题都可以先尝试分析相邻的值(数组的相邻元素, 图的相邻点), 看看它们是否存在一些关系; 另外还可以尝试增加维度/状态找相邻点, 以及找当前值与之前多个值的关系等等
  • 感兴趣的小伙伴可以在我的公众号"每日精选算法题"中的聊天框中回复 股票, 那个系列里有几个比较进阶的动态规划题目

实现

  • 定义 dp 数组, 初始化dp[0] = 0, dp[1] = 1
  • 然后从 2 开始循环直到 n, 每次套用dp[n] = dp[n-1] + dp[n-2] 即可
  • 特别注意根据题目要求, 每次相加得到新的 dp 值时需要取模 (如果最后结果再取模的话, 对于 python 而言由于涉及大数操作, 速度会慢一些, 而对于 C/Java 等语言的话则可能会导致溢出)
  • 优化
    • 注意到当前 dp 值只和前面两个 dp 值有关, 所以我们完全可以只使用两个变量 preprepre, 分别代表当前下标的前一个和再上一个下标的 dp 值 dp[n-1]dp[n-2].
    • 然后当前的 dp 值就更新为它们两个的和
    • 最后更新当前 dp 值为新的 pre, 原来的 pre 就是新的 prepre
    • 而最终结果就是 pre 了, 因为遍历完 n 之后, 当前 dp 值已经更新为 pre

复杂度

  • 时间复杂度 O(N)
    • 需要遍历整个数组一遍
  • 空间复杂度 O(1)
    • 优化后只需要几个变量即可

代码

class Solution:
    def fib(self, n: int) -> int:
        if n < 2:
            # n小于2的情况, 根据初始化, 直接返回n即可
            return n
        prepre, pre = 0, 1
        for i in range(2, n + 1):
            # 同时更新新的prepre和pre, 这里利用了python的语言特性, 同时赋值的时候不会相互影响, 其他语言可能需要额外一个tmp变量来先保存原来的pre了
            prepre, pre = pre, (prepre + pre) % 1000000007
        return pre

大家可以在下面这些地方找到我~

我的知乎专栏

我的 CSDN

我的 Leetcode

我的牛客网博客

我的公众号: 每日精选算法题, 欢迎大家扫码关注~

每日精选算法题 - 微信扫一扫关注我

你可能感兴趣的:(Leetcode,算法,python,编程语言,数据结构,leetcode)