传统解法

提到斐波那契数列(Fibonacci Sequence),首先想到的是经典的动规(DP)算法。

时间复杂度O(n),这里空间复杂度可以优化到O(1)。代码如下:

int fib_n(int n)
{
int dp[] = {, };
if (n <= ) return dp[n]; for (int i = ; i <= n; ++i)
dp[i % ] = dp[(i - ) % ] + dp[(i - ) % ]; return dp[n % ];
}

但是初次接触O(logn)解法有如醍醐灌顶,叹为观止……

O(logn)解法

思路来源 1

考虑一个求幂运算。比如求an,一般来说需要n次累乘,时间复杂度显然是O(n)。实际上可以通过递归达到一种更优化的效果:

an = (an/2)2 * an%2

这里的n/2是取整,如5/2=2。这样就可以实现相当于二分的效果,时间复杂度为O(logn)。

思路来源2

对于Fib数列an(n ≥ 0),可以通过矩阵乘法的方式进行递推:

进而可以得到:

这样就(很机智地)把Fib数列问题转化成了一个求矩阵幂的运算。

解题方法

结合以上思路,首先将其转化为矩阵求幂问题,然后进行二分,O(logn)解法由此诞生。再次感慨人类清奇的脑洞 _(:з」∠)_

以下是代码:

int** mult(int** m1, int** m2)
{
int** res = new int*[];
for (int i = ; i < ; ++i) res[i] = new int[]; res[][] = m1[][] * m2[][] + m1[][] * m2[][];
res[][] = m1[][] * m2[][] + m1[][] * m2[][];
res[][] = m1[][] * m2[][] + m1[][] * m2[][];
res[][] = m1[][] * m2[][] + m1[][] * m2[][]; return res;
} int** recur(int x)
{
if (x == ) {
int** res = new int*[];
for (int i = ; i < ; ++i) res[i] = new int[];
res[][] = res[][] = ;
res[][] = res[][] = ;
return res;
}
if (x == ) {
int** res = new int*[];
for (int i = ; i < ; ++i) res[i] = new int[];
res[][] = res[][] = res[][] = ;
res[][] = ;
return res;
}
int** half = recur(x / );
return mult(mult(half, half), recur(x % ));
} // time: O(logn)
int fib_logn(int n)
{
if (n == || n == ) return ;
int** mat = recur(n - );
return mat[][] + mat[][];
}

结果比较

简单比较一下后者的优化效果,为了是效果更明显,这里将参数设置成一个较大的数(如109),以下是代码以及结果:

void test()
{
const int num = 1e9;
clock_t t1, t2; t1 = clock();
fib_n(num);
t2 = clock();
printf("O(n): %.4f s\n", (double)(t2 - t1) / CLOCKS_PER_SEC); t1 = clock();
fib_logn(num);
t2 = clock();
printf("O(logn): %.4f s\n", (double)(t2 - t1) / CLOCKS_PER_SEC); }

 结果

O(n)算法的速度达到了男子百米的世界顶级水平,而O(logn)只表现出一脸不屑……

好吧,我服……那我把logn的多跑几次 for (int i = ; i < ; ++i) fib_logn(num);

那么结果也很明显了,O(logn)算法表现惊艳!

THE END

Fibonacci 数列O(logn)解法的更多相关文章

  1. 程序员面试题精选100题(16)-O(logn)求Fibonacci数列[算法]

    作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:定义Fibonacci数列如下: /  0                      n=0 f(n)=      ...

  2. Fibonacci数列的解法

    Fibonacci数列的解法: 1.递归算法 递归的概念,我说不清楚,语文不好.但是核心思想,我认为就是入栈出栈.比方说,你想要求得某个结果,如果一步求解不出来,那么先把最后一步的计算步骤进栈,先不考 ...

  3. 《面试题精选》15.O(logn)求Fibonacci数列

    题目:定义Fibonacci数列例如以下: /    0                      n=0 f(n)=      1                      n=1          ...

  4. 【编程题目】题目:定义 Fibonacci 数列 输入 n,用最快的方法求该数列的第 n 项。

    第 19 题(数组.递归):题目:定义 Fibonacci 数列如下:/ 0 n=0f(n)= 1 n=1/ f(n-1)+f(n-2) n=2输入 n,用最快的方法求该数列的第 n 项. 思路:递归 ...

  5. fibonacci 数列及其应用

    fibonacci 数列及其延展 fibonacci计算 fibonacci数列是指 0,1,1,2,3,5,8,13,21……这样自然数序列,即从第3项开始满足f(n)=f(n-1)+f(n-2): ...

  6. 青蛙跳台阶(Fibonacci数列)

    问题 一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级.求该青蛙跳上一个n 级的台阶总共有多少种跳法. 思路 当n=1时,只有一种跳法,及f(1)=1,当n=2时,有两种跳法,及f(2)=2,当n= ...

  7. 【费式数列(Fibonacci数列)】

    /* 说明: Fibonacci为1200年代的欧洲数学家,在他的着作中曾经提到:若有一只兔子每个月生一只小兔子,一个月后也开 始生产.起初只有一只兔子,一个月后就有两只兔子,二个月后就有三只兔子,三 ...

  8. 常系数线性递推的第n项及前n项和 (Fibonacci数列,矩阵)

      (一)Fibonacci数列f[n]=f[n-1]+f[n-2],f[1]=f[2]=1的第n项的快速求法(不考虑高精度). 解法: 考虑1×2的矩阵[f[n-2],f[n-1]].根据fibon ...

  9. Fibonacci 数列算法分析

    /************************************************* * Fibonacci 数列算法分析 ****************************** ...

随机推荐

  1. 利用instsrv和srvany来手动安装服务

    Windows提供了两个小工具instsrv.exe和srvany.exe来把任何应用包装成windows服务.顾名思义instsrv(install service)是用来安装服务的,而srvany ...

  2. Single Number leetcode

    Given an array of integers, every element appears twice except for one. Find that single one. Note:Y ...

  3. HTTP 返回状态代码详解

    1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态代码. 100(继续)请求者应当继续提出请求. 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分:101(切换协议)请求者已要求服 ...

  4. Docker存储驱动之ZFS简介

    ZFS是下一代的文件系统,支持了很多存储高级特性,如卷管理.快照.和校验.压缩和重复删除技术.拷贝等. ZFS由Sun公司创建,现属于Oracle,ZFS是开源的,并基于CDDL license.因为 ...

  5. java-信息安全(五)-非对称加密算法RSA

    概述 信息安全基本概念: RSA算法(Ron Rivest.Adi Shamir.Leonard Adleman,人名组合) RSA RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rive ...

  6. 构建微服务-使用OAuth 2.0保护API接口

    微服务操作模型 基于Spring Cloud和Netflix OSS 构建微服务-Part 1 基于Spring Cloud和Netflix OSS构建微服务,Part 2 在本文中,我们将使用OAu ...

  7. TCP/IP笔记(三)数据链路层

    数据链路的作用 数据链路层的协议定义了通过通信媒介互连的设备之间传输的规范.通信媒介包括双绞线电缆.同轴电缆.光纤.电波以及红外线等介质.此外,各个设备之间有时也会通过交换机.网桥.中继器等中转数据. ...

  8. js高级程序设计学习之高级函数

    安全的类型检测 function isArray(value){ return Object.prototype.toString.call(value) === "[object Arra ...

  9. iOS开发之数据存储之Preference(偏好设置)

    1.概述 很多iOS应用都支持偏好设置,比如保存用户名.密码.字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能. 每个应用都有个NSUserDefaults实例,通过它来存取偏好 ...

  10. Linux下python开发环境的准备

    升级python 安装依赖: yum install lrzsz zlib zlib-devel  openssl  readline-deve gcc  ibffi-devel python-dev ...