传统解法

提到斐波那契数列(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. Java垃圾回收学习笔记

    通常来说,要写Java代码,你基本上都没必要听说垃圾回收这个概念的.这不,对于已经写了5年多Java代码的我来说,我还没有哪次经历说是需要使用垃圾回收方面的知识来解决问题的.但是,我依然督促自己花了几 ...

  2. java基础:数组的拼接

  3. android sdk tools 一览

    ANDROID SDK ADKROID SDK的工具划分为两部分,一部分是SDK tools,与平台无关,另一部分是Platform tools支持最新的安卓平台   SDK tools有 SDK m ...

  4. KoaHub平台基于Node.js开发的Koa 连接支付宝插件代码信息详情

    KoaHub平台基于Node.js开发的Koa 链接支付宝插件代码信息详情 easy-alipay alipay payment & notification APIs easy-alipay ...

  5. 1592: [Usaco2008 Feb]Making the Grade 路面修整

    1592: [Usaco2008 Feb]Making the Grade 路面修整 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 428  Solv ...

  6. 1734: [Usaco2005 feb]Aggressive cows 愤怒的牛

    1734: [Usaco2005 feb]Aggressive cows 愤怒的牛 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 217  Solved: ...

  7. CentOS7搭建Confluence Wiki

    前言 在艾佳生活实习时,有三款团队协作系统特别喜欢:Wiki.Jira和Jenkins.对于Jenkins的搭建,之前<自动部署工具Jenkins>有过记录.这次,搭建一个Wiki,作为知 ...

  8. .Net轻量级ORM-NPoco的使用方法-摘自NPoco国外官方Wiki

    文章引用自NPoco官方Wiki,地址:https://github.com/schotime/NPoco/wiki,因公司网络不稳定,有时无法访问,特将其摘抄. Home Adam Schroder ...

  9. Android使用Sugar ORM创建数据库报no such table:...的解决方法

    在学习使用Android开源框架Sugar ORM时,只是做了开始的创建数据库的操作就报出如下的异常信息 android.database.sqlite.SQLiteException: no suc ...

  10. “倔驴”一个h5小游戏的实现和思考(码易直播)——总结与整理

    3月23日晚上8点半(中国队火拼韩国的时候),做了一期直播分享.15年做的一个小游戏,把核心代码拿出来,现场讲写了一遍,结果后面翻车了,写错了两个地方,导致运行效果有点问题,直播边说话边写代码还真不一 ...