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 数列算法分析 ****************************** ...
随机推荐
- C#:查询某年(1900-2100)某月的日历
using System;using System.Collections.Generic;public class Program { /********************主函数 ...
- 1596: [Usaco2008 Jan]电话网络
1596: [Usaco2008 Jan]电话网络 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 601 Solved: 265[Submit][S ...
- MD5加密 32位
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 18.0px Menlo } p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; ...
- frameset标签设计页面
重要事项:不能将 <frameset></frameset> 标签放在<body></body> 标签里.且 HTML5 已经不支持 frameset ...
- python IP地址转16进制
python IP地址转16进制 第一种方法: 通过socket.inet_aton实现 import socket from binascii import hexlify ary='192.168 ...
- Omi框架学习之旅 - Hello World 及原理说明
学什么东西都从hello world开始, 我也不知道为啥. 恩,先上demo代码, 然后提出问题, 之后解答问题, 最后源码说明. hello world - demo: class Hello e ...
- windows phone 8.1 开发:后台任务详解
原文出自:http://www.bcmeng.com/backtask/ 小梦今天给大家分享一下windows phone 8.1中的后台任务如何实现,许多应用都会用到后台任务,所以我们必须得掌握. ...
- JavaEE开发之Spring中的依赖注入与AOP
上篇博客我们系统的聊了<JavaEE开发之基于Eclipse的环境搭建以及Maven Web App的创建>,并在之前的博客中我们聊了依赖注入的相关东西,并且使用Objective-C的R ...
- java学习笔记 --- 方法
一.方法 (1)方法:就是完成特定功能的代码块. 注意:在很多语言里面有函数的定义,而在Java中,函数被称为方法. (2)格式: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 ...
- node.js平台下,利用cookie实现记住密码登陆(Express+Ejs+Mysql)
本博文需有node.js+express+mysql入门基础,若基础薄弱,可参考博主的其他几篇node.就是博文: 1.下载Mysql数据库,安装并配置 创建用户表供登录使用: 2.node.js平台 ...