• 剑指offer(C++)-JZ10:斐波那契数列(时间复杂度O(logn)解法)


    作者:翟天保Steven
    版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

    题目描述:

    大家都知道斐波那契数列,现在要求输入一个正整数 n ,请你输出斐波那契数列的第 n 项。

    斐波那契数列是一个满足如下条件的数列

    数据范围:1≤n≤40

    要求:空间复杂度O(1),时间复杂度O(n) ,本题也有时间复杂度O(logn) 的解法

    示例:

    输入:

    4
    

    返回值:

    3
    

    说明:

    根据斐波那契数列的定义可知,fib(1)=1,fib(2)=1,fib(3)=fib(3-1)+fib(3-2)=2,fib(4)=fib(4-1)+fib(4-2)=3,所以答案为3。

    解题思路:

    本题考察算法-动态规划算法的使用,和青蛙跳台阶一样的解法,但本文不探究那些基础解法,来研究下如何实现时间复杂度为O(logn)的解法。思路如下。

    斐波那契数列为:F(n)=F(n-1)+F(n-2)

    则有如下公式成立:\begin{bmatrix} F(n+1)\\ F(n) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}\begin{bmatrix} F(n)\\ F(n-1) \end{bmatrix}

    当n=2时,有:\begin{bmatrix} F(3)\\ F(2) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}\begin{bmatrix} F(2)\\ F(1) \end{bmatrix}

    不难得出:\begin{bmatrix} F(n)\\ F(n-1) \end{bmatrix}=\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^{n-2}\begin{bmatrix} F(2)\\ F(1) \end{bmatrix}=\begin{bmatrix} m & n\\ p & q \end{bmatrix}\begin{bmatrix} F(2)\\ F(1) \end{bmatrix}

    则:F(n)=mF(2)+nF(1)

    当知道n以后,只需要求解元矩阵的n-2次方即可,对矩阵的高幂求解,可运用快速幂算法实现提速。

    快速幂算法是将高次幂拆解为多个低次幂的组合,如:

    X^{13}=X^{8}X^{4}X

    13转换为2进制是1101,即8+4+1,那我们如果求解矩阵的13次方,只需要求一次X,X的平方,X的四次方,X的八次方,然后取X的八次方乘X的四次方乘X即可,这样省下了许多运算过程。时间复杂度为O(logn),如果用遍历的方法求解矩阵的13次方,就相当于执行了13次操作,这样的复杂度就是O(n)。

    测试代码:

    1. class Solution {
    2. public:
    3. int Fibonacci(int n) {
    4. // 12时为1
    5. if(n == 1 || n == 2)
    6. return 1;
    7. // 根据斐波那契数列可知,元矩阵如下
    8. vector<vector<int>> element={{1,1},{1,0}};
    9. // 元矩阵高幂运算,用快速幂算法求解
    10. vector<vector<int>> result=Counting(element, n-2);
    11. return result[0][0]+result[0][1];
    12. }
    13. // 快速幂算法
    14. vector<vector<int>> Counting(vector> element,int n){
    15. // 初始化为单元矩阵
    16. vector<vector<int>> result={{1,0},{0,1}};
    17. // 基数矩阵
    18. vector<vector<int>> base=element;
    19. // 右移幂数,可快速完成求解
    20. for(;n!=0;n>>=1)
    21. {
    22. // 当前位数为1时,矩阵相乘
    23. if((n&1)!=0)
    24. {
    25. result=MatrixCalculation(result, base);
    26. }
    27. // 基数矩阵升级幂数
    28. base=MatrixCalculation(base, base);
    29. }
    30. return result;
    31. }
    32. // 矩阵求解
    33. vector<vector<int>> MatrixCalculation(vector> a,vector> b){
    34. vector<vector<int>> result(a.size(),vector(b[0].size(),0));
    35. for(int i=0;i<a.size();++i)
    36. {
    37. for(int j=0;j<b[0].size();++j)
    38. {
    39. for(int k=0;k<a[0].size();++k)
    40. {
    41. result[i][j]+=a[i][k]*b[k][j];
    42. }
    43. }
    44. }
    45. return result;
    46. }
    47. };

    用什么容器都可以,原理懂了,实现方法有很多种~

  • 相关阅读:
    全网最全的知识库管理工具综合评测和推荐:FlowUs、Baklib、简道云
    BUUCTF reverse wp 91 - 95
    Apache atlas 元数据管理治理平台使用和架构
    Javascript 如何监听input输入框值的实时变化
    10.3 小任务
    头歌【第2关:有序单链表中值相同的多余结点的删除操作】
    基于STM32设计的车库监控报警系统
    Web前端开发涉及的一些技术
    7月销量被哪吒、零跑反超,“蔚小理”怎么了?
    Springboot设置文件上传大小限制
  • 原文地址:https://blog.csdn.net/zhaitianbao/article/details/127884781