Fibonacci 数列O(logn)解法
传统解法
提到斐波那契数列(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)解法的更多相关文章
- 程序员面试题精选100题(16)-O(logn)求Fibonacci数列[算法]
作者:何海涛 出处:http://zhedahht.blog.163.com/ 题目:定义Fibonacci数列如下: / 0 n=0 f(n)= ...
- Fibonacci数列的解法
Fibonacci数列的解法: 1.递归算法 递归的概念,我说不清楚,语文不好.但是核心思想,我认为就是入栈出栈.比方说,你想要求得某个结果,如果一步求解不出来,那么先把最后一步的计算步骤进栈,先不考 ...
- 《面试题精选》15.O(logn)求Fibonacci数列
题目:定义Fibonacci数列例如以下: / 0 n=0 f(n)= 1 n=1 ...
- 【编程题目】题目:定义 Fibonacci 数列 输入 n,用最快的方法求该数列的第 n 项。
第 19 题(数组.递归):题目:定义 Fibonacci 数列如下:/ 0 n=0f(n)= 1 n=1/ f(n-1)+f(n-2) n=2输入 n,用最快的方法求该数列的第 n 项. 思路:递归 ...
- fibonacci 数列及其应用
fibonacci 数列及其延展 fibonacci计算 fibonacci数列是指 0,1,1,2,3,5,8,13,21……这样自然数序列,即从第3项开始满足f(n)=f(n-1)+f(n-2): ...
- 青蛙跳台阶(Fibonacci数列)
问题 一只青蛙一次可以跳上 1 级台阶,也可以跳上2 级.求该青蛙跳上一个n 级的台阶总共有多少种跳法. 思路 当n=1时,只有一种跳法,及f(1)=1,当n=2时,有两种跳法,及f(2)=2,当n= ...
- 【费式数列(Fibonacci数列)】
/* 说明: Fibonacci为1200年代的欧洲数学家,在他的着作中曾经提到:若有一只兔子每个月生一只小兔子,一个月后也开 始生产.起初只有一只兔子,一个月后就有两只兔子,二个月后就有三只兔子,三 ...
- 常系数线性递推的第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 ...
- Fibonacci 数列算法分析
/************************************************* * Fibonacci 数列算法分析 ****************************** ...
随机推荐
- Java系统属性与Preferences API的简单介绍
系统属性在和Preferences API都是键值对,前者只能当前应用程序中共享数据,而后者可以在用户的各个应用或用户之间共享数据. 系统属性 Java 的系统属性决定了 Java 程序实际运行的环境 ...
- 警惕!MySQL成数据勒索新目标
据最新报道显示,继MongoDB和Elasticsearch之后,MySQL成为下个数据勒索目标,从2月12日凌晨开始,已有成百上千个开放在公网的MySQL数据库被劫持,删除了数据库中的存储数据,攻击 ...
- bat文件的一些小技巧
bat文件的简介: bat文件是dos下的批处理文件.批处理文件是无格式的文本文件,它包含一条或多条命令.它的文件扩展名为 .bat 或 .cmd.在命令提示下键入批处理文件的名称,或者双击该批处理文 ...
- java如何在一个范围内产生多个不等的随机数
import java.util.Random; //随机产生0-max之间num个不重复的整数 public class 产生多个不同随机数 { private static int num,max ...
- Office 365开发概述及生态环境介绍(一)
原文于2017年3月13日首发于LinkedIn,请参考这个链接 离上一篇文章,很快又过去了两星期的时间.今天抓紧晚上的时间,开始了Office 365开发系列文章的第一篇,我会帮助大家回顾一下过去O ...
- 小命令tac、cat、rev的用法
cat:输出文件的内容(正序,由上至下) tac:输出文件的内容(倒序,由下至上) rev: 反转每行的文字内容,行号不变 示例:建立一个文件夹 1.演示cat效果 按原始样式正常显示 2.演示tac ...
- mui学习链接
http://dev.dcloud.net.cn/mui/snippet/ http://www.bcty365.com/content-146-2453-1.html hbuilder转rem值: ...
- Repaints and Reflows 重绘和重排版
当浏览器下载完所有页面HTML标记,JavaScript,CSS,图片之后,它解析文件并创建两个内部数据 一棵DOM树 表示页面结构 Normal 0 7.8 磅 0 2 false false fa ...
- 腾讯QQ会员技术团队:以手机QQ会员H5加速为例,为你揭开sonic技术内幕
目前移动端越多越多的网页开始H5化,一方面可以减少安装包体积,另一方面也方便运营.但是相对于原生界面而言,H5的慢速问题一定被大家所诟病,针对这个问题,目前手Q存在几种方案,最常见的便是离线包方案,但 ...
- Eclipse中的快捷键快速生成常用代码(例如无参、带参构造,set、get方法),以及Java中重要的内存分析(栈、堆、方法区、常量池)
(一)Eclipse中的快捷键: ctrl+shift+f自动整理选择的java代码 alt+/ 生成无参构造器或者提升信息 alt+shift+s+o 生成带参构造 ctrl+shift+o快速导 ...