IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 剑指Offer 10-Ⅰ.斐波那契数列(C++) -> 正文阅读

[C++知识库]剑指Offer 10-Ⅰ.斐波那契数列(C++)

前言

利用「尾递归」、「动态规划」、「递推」和「矩阵快速幂」来解决问题。

剑指Offer 10-Ⅰ.斐波那契数列

问题描述

写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项(即 F(N))。斐波那契数列的定义如下:
F(0) = 0,   F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 01 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+71000000007),如计算初始结果为:1000000008,请返回 1

示例

|| 输入:n = 2
|| 输出:1

尾递归

一开始直接用普通递归做,n稍微大一点的时候就超出时间限制了,于是想到「尾递归」

  • 递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储,因此递归次数过多容易造成栈溢出。
    3递归.png

  • 尾递归是把当前的运算结果放在参数里传递给下层函数,只用保存最后一个函数堆栈。
    3尾递归.png

代码

class Solution { 
public:
    int fib(int n) {
        return fibTail(n,0,1);
    }
    int fibTail(int n,int curr,int next){
        int mod = 1e9+7;
        if(n==0)
            return curr;
        return fibTail(n-1,next%mod,(curr+next)%mod);
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

动态规划

题中已经给出了状态转移方程
F(N) = F(N - 1) + F(N - 2)
与n值对应,n是从0开始的,我们申请一个大小为 n+1 的数组 dp,
定义 dp[i] 为斐波那契数列第 i 项的值,
那么 dp[n] 为斐波那契数列第 n 项的值,
dp[0]=0 和 dp[1]=1 为两个初始状态,
利用dp[i] = dp[i-1] + dp[i-2]循环计算dp[i]的值。

代码

class Solution { 
public:
    int fib(int n) {
        if(n<=1)
            return n;
        int mod = 1e9+7;
        int dp[n+1];
        dp[0] = 0;
        dp[1] = 1;
        for(int i=2;i<=n;++i){
            dp[i] = dp[i-1] + dp[i-2];
            dp[i] %= mod;
        }
        return dp[n];
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)

递推

根据 F(N) = F(N - 1) + F(N - 2),我们知道 F(N) 的值只与 F(N - 1) 和 F(N - 2) 有关,那就可以用递推来实现动态规划,也就不需要申请一个数组来保存过程中的值,我们只申请三个常量即可。

代码

class Solution { 
public:
    int fib(int n) {
        if(n<=1)
            return n;
        int mod = 1e9+7;
        int a = 0,b = 1;
        int sum = a + b;
        for(int i=2;i<n;++i){
            a = b;
            b = sum;
            sum = (a + b)%mod;
        }
        return sum;
    }
};
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

矩阵快速幂

本题可以根据构造合适的矩阵乘法来实现 F(N) = F(N - 1) + F(N - 2) 中 F(N)、F(N - 1) 和 F(N - 2) 之间的依赖关系,利用 F(N - 1) 和 F(N - 2) 推导出 F(N) 。
根据矩阵乘法构造出
[ F ( n ) F ( n ? 1 ) ] = [ F ( n ? 1 ) + F ( n ? 2 ) F ( n ? 1 ) ] = [ 1 1 1 0 ] × [ F ( n ? 1 ) F ( n ? 2 ) ] \left[ \begin{array}{l} F(n)\\ F(n - 1) \end{array} \right] = \left[ \begin{array}{l} F(n - 1) + F(n - 2)\\ F(n - 1) \end{array} \right] = \left[ {\begin{matrix} 1&1\\ 1&0 \end{matrix}} \right] \times \left[ \begin{array}{l} F(n - 1)\\ F(n - 2) \end{array} \right] [F(n)F(n?1)?]=[F(n?1)+F(n?2)F(n?1)?]=[11?10?]×[F(n?1)F(n?2)?]

m a t = [ 1 1 1 0 ] mat = \left[ {\begin{matrix} 1&1\\ 1&0 \end{matrix}} \right] mat=[11?10?]
我们已知的初始状态为
[ F ( 0 ) F ( 1 ) ] \left[ \begin{array}{l} F(0)\\ F(1) \end{array} \right] [F(0)F(1)?]

推出
[ F ( n ) F ( n ? 1 ) ] = m a t × m a t × ? m a t × [ F ( 0 ) F ( 1 ) ] = m a t × m a t × ? m a t × [ 0 1 ] = m a t n ? 1 × [ 0 1 ] \left[ \begin{array}{l} F(n)\\ F(n - 1) \end{array} \right] = mat \times mat \times \cdots mat \times \left[ \begin{array}{l} F(0)\\ F(1) \end{array} \right] = mat \times mat \times \cdots mat \times \left[ \begin{array}{l} 0\\ 1 \end{array} \right] = ma{t^{n - 1}} \times \left[ \begin{array}{l} 0\\ 1 \end{array} \right] [F(n)F(n?1)?]=mat×mat×?mat×[F(0)F(1)?]=mat×mat×?mat×[01?]=matn?1×[01?]
所以我们可以利用快速幂求出
m a t n ? 1 ma{t^{n - 1}} matn?1
直接循环累乘也可以求出来,但是时间复杂度为O(n),而快速幂算法每一步都把指数分成两半,用相应的底数做平方运算,所需要执行的循环次数也变小,时间复杂度为O(log n)。

代码

class Solution { 
public:
    int mod = 1e9+7;
    vector<vector<long>> mul(vector<vector<long>>& a, vector<vector<long>>& b){
        int arow = a.size();    //a的行数
        int brow = b.size();    //b的行数
        int bcol = b[0].size(); //b的列数
        vector<vector<long>> ans(arow,vector<long>(bcol,0));    //arow行bcol列,初始化为0
        for(int i=0;i<arow;++i){
            for(int j=0;j<bcol;++j){
                for(int k=0;k<brow;++k){
                    ans[i][j] += a[i][k] * b[k][j];
                    ans[i][j] %= mod;
                }
            }
        }
        return ans;
    }
    int fib(int n) {
        if (n <= 1) 
            return n;
        vector<vector<long>> mat = {{1, 1},
                                    {1, 0}};
        vector<vector<long>> ans = {{1},
                                    {0}};
        int x = n - 1;
        while (x != 0) {
            if ((x & 1) != 0) ans = mul(mat, ans);
            mat = mul(mat, mat);
            x >>= 1;
        }
        return ans[0][0] % mod;
    }
};
  • 时间复杂度:O(log n)
  • 空间复杂度:O(1)

微信公众号文章

剑指Offer 10-Ⅰ.斐波那契数列

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-05 10:37:43  更:2021-09-05 10:39:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 20:57:52-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码