***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************

一、 引言

今天早上,例行随便看看。

看到文章 ->  面试中怎样剔除“鱼目混珠”的程序猿

看到里面这段:

  1. 招聘程序设计人员,尤其是提到代码,最流行的将鱼目混珠的程序猿剔除的问题是 Fizz-Buzz 測试。
  2.  
  3. 假设一个程序猿无法在10-15分钟之间写出一个 Fizz-buzz,那他可能须要很多其它的锻炼。也许根本没有准备好。另外一个方法就是让他们写 Fibonacci series(斐波纳契数列),并请他们优化一下。大家都知道 Fibonacci 是非经常见的,可是你可能会非常吃惊的看到这些程序猿非常难在之上写出这些数列,即使是在 IDE 上也写不出来。

恩,话说不懂什么事Fizz-buzz測试。。

于是Wiki了一下 -> http://en.wikipedia.org/wiki/Fizz_buzz

好吧,就是个报数游戏,3或3的倍数 喊Fizz。5或5的倍数喊Buzz,假设既是3又是5的倍数喊FizzBuzz。

重点是后面的那个Fibonacci 的优化。

我仅仅知道 递归和递推两种,上网搜了搜,果真优化非常多

看到了 时间复杂度O(log(n)) 空间复杂度O(1)的方法。

就想学习一下

二、Fizz-Buzz

这个我认为没有难度,

这是我写的:

  1. <span style="font-family:Comic Sans MS;font-size:14px;">// Fizz Buzz
  2. void FizzBuzz( int n )
  3. {
  4. bool isFZ;
  5. for( int i = 1 ; i <= n ; ++i )
  6. {
  7. isFZ=false;
  8. if( i % 3 == 0 ) {cout<<"Fizz";isFZ=true;}
  9. if( i % 5 == 0 ) {cout<<"Buzz";isFZ=true;}
  10. if( !isFZ ) cout<<i;
  11. cout<<" ";
  12. if( i % 10 == 0 ) cout<<endl;
  13. }
  14. }</span>

非常easy。但我总认为有点繁杂。

希望会更好的方法的。留下代码,学习一下~

三、Fibonacci的优化

简单说一下Fibonacci 数列

有一种理想型生物,都拿兔子来说= =。

刚開始有这么一对兔子。每月初能够生一对兔子。而刚出生的兔子到第三个月初開始,也能够生每月初生一对兔子。

这样下去,到第n个月,会有多少对兔子?

来一个表格:

月份: 012
3 4
56...
n

①兔: 001
1 2
35...
n-1_成年兔+n-1_②兔

推导: n-1_成年兔 = n-2_成年兔+n-2_②兔,n-1_②兔=n-2_①兔

n-1_成年兔+n-1_②兔= n-2_兔总

②兔: 000
1 1
23...
n-1_①兔

成年兔: 011
1 2
35...
n-1_成年兔+n-1_②兔

兔总: 012
3 5
813...
n-1_兔总+n-2兔总

PS:①兔表示一个月大的兔子。②兔即两个月大兔子。里面的数字是兔子的对数。

这是推倒出来

第n个月的 ①兔对数 等于 该月成年兔对数

第n个月的 ②兔对数 等于 第 n-1月的①兔对数

第n个月的 成年兔对数 等于 第n-1月的成年兔对数+②兔对数

然后再依据n-1 推 n-2 的发现

第n个月兔子对数 等于 第n-1月 与 第n-2月 兔子对数之和。

这是按我的理解思路,讲述的。。

有点绕。不知道懂了木有。。。

主要的Fibonacci概念说完了,如今看它们的解法:

1.最简单暴力好读的——递归方法

时间复杂度:O(2^n)

空间复杂度:数字过大可能导致 栈溢出

  1. <span style="font-family:Comic Sans MS;font-size:14px;">int digui( int n )
  2. {
  3. if( n == 0 )
  4. return 0;
  5. else if( n == 1 )
  6. return 1;
  7. else
  8. return ( digui(n-1) + digui(n-2) );
  9. }</span>

2.省空间也省了时间的,递归进阶——递推方法

时间复杂度:O(n)

空间复杂度:O(n)

  1. <span style="font-family:Comic Sans MS;font-size:14px;">// 普通递推算法
  2. int* ditui( int n )
  3. {
  4. int* arr = new int[n+1];
  5. arr[0]=0,arr[1]=1;
  6.  
  7. for( int i = 2 ; i <= n ; ++i )
  8. arr[i]=arr[i-1]+arr[i-2];
  9.  
  10. return arr;
  11. }</span>

3.继续优化——优化递推法

我们能够看到,假设求第n个Fibonacci数,

我们仅仅须要知道第n-1和第n-2个的Fibonacci数就可以。

前面的不须要存储。

所以。就有了更优化。

时间复杂度:O(n)

空间复杂度:O(1)

  1. <span style="font-family:Comic Sans MS;font-size:14px;">// 递推算法优化
  2. int ditui_opt( int n )
  3. {
  4. if( n < 2 ) return n;
  5. int i = 1,pre1=0,pre2=1;
  6. while( i < n )
  7. {
  8. pre2 = pre2 + pre1;
  9. pre1 = pre2 - pre1;
  10. ++i;
  11. }
  12. return pre2;
  13. }</span>

4.更优化的——矩阵法

时间复杂度:O(log(n) )

空间复杂度:数字过大可能导致 栈溢出

递归、递推已经无法优化时间复杂度了,

空间都到了O(1)了。也没法再精进了,

so,有没有别的方法来进行进一步优化呢?

Of course!

我们能够发现。事实上f(n) 都是 f(0)和f(1) 有关的:

f(2) = f(1) + f(0);

f(3) = f(2) + f(1) = 2*f(1) + f(0);

f(4) = f(3) + f(2) = 3*f(1) + 2*f(0);

.......

所以未来的f(n)一定等于:

f(n) = a*f(1) + b*f(0);

但是,怎样求a和b呢?

通过矩阵行列式,能够推演出:

这样。关键就是求矩阵的次方了,

假设直接计算。那么时间复杂度是O(n),根本就没有什么优化。

所以,此时,我们就要用二分法(分治法)来解决

M^a =  M^(a/2) * M^(a/2) = ....

这样,时间复杂度能够优化到O(log(n) )!

  1. <span style="font-family:Comic Sans MS;font-size:14px;">// 矩阵优化 方法
  2.  
  3. // 构造个矩阵结构体
  4. struct Matrix
  5. {
  6. int m0,m1,m2,m3;
  7. };
  8. // 矩阵乘法
  9. Matrix mat_mul( Matrix mtx1 , Matrix mtx2 )
  10. {
  11. Matrix mat;
  12. mat.m0 = mtx1.m0 * mtx2.m0 + mtx1.m1 * mtx2.m2;
  13. mat.m1 = mtx1.m0 * mtx2.m1 + mtx1.m1 * mtx2.m3;
  14. mat.m2 = mtx1.m2 * mtx2.m0 + mtx1.m3 * mtx2.m2;
  15. mat.m3 = mtx1.m2 * mtx2.m1 + mtx1.m3 * mtx2.m3;
  16. return mat;
  17. }
  18. // 矩阵乘方
  19. Matrix mat_pow( int k )
  20. {
  21. Matrix mat;
  22. if( k == 1 )
  23. {
  24. mat.m0=1;
  25. mat.m1=1;
  26. mat.m2=1;
  27. mat.m3=0;
  28. }
  29. else if( k % 2 == 0)
  30. {
  31. mat = mat_pow( k/2 );
  32. mat = mat_mul( mat , mat );
  33. }
  34. else
  35. {
  36. mat = mat_pow( (k - 1) / 2 );
  37. mat = mat_mul( mat , mat );
  38. mat = mat_mul( mat , mat_pow(1) );
  39. }
  40. return mat;
  41. }
  42. // 最后求Fibonacci
  43. int fib_matrix( int n )
  44. {
  45. if( n < 2 ) return n;
  46.  
  47. Matrix mat;
  48. mat = mat_pow(n-1);
  49.  
  50. int ans;
  51. ans = mat.m0 + mat.m1;
  52. return ans;
  53. }</span>

这样的方法时间上压缩到了log(n),但是空间上,由于二分法,算是递归的过程,

有可能会导致 栈溢出。

于是乎,又有了优化方法。

5.优化中的优化

时间复杂度:O(log(n))

空间复杂度:O(1)

没错。就是O(1)。

压缩空间复杂度。并且是对于递归,

并且。这是对于矩阵法的优化,

难度,肯定在于

1 1

1 0

矩阵的n-1次方的求法,

将这个用递推实现,

我们会发现:

f(1)——为简化。f(1)表示 n=1时 矩阵的n-1次方。用mat代表矩阵

f(1) = 1。

f(2) = mat

f(3) = f(2)* f(1)

f(4) = f(3)* f(1) = f(2) * f(2)

f(5) = f(4)* f(1)

f(6) = f(5)* f(1) = f(3) * f(3)

......

看到规律了吗?

就是说,当f(n)中

n为偶数,

f(n)= f(n/2) * f(n/2)

n为奇数

f(n)= f(n-1)* f(1)

因此。我们不须要将所有的数所有存储就可以计算了。

算法之路。博大精深啊。

***************************************转载请注明出处:http://blog.csdn.net/lttree******************************************

FizzBuzz and Fibonacci优化的更多相关文章

  1. Fibonacci快速实现(优化)

    斐波那契数列的通俗解法是利用递推公式进行递归求解,我们可以更优化的去解决它. 方法一:通项公式 斐波那契数列的递推公式是f(n)=f(n-1)+f(n-2),特征方程为:x2=x+1,解该方程得(1+ ...

  2. 关于fibonacci数列用JS写的一点小优化

    直接上代码 var month = prompt("请输入月数:") function fibobo(x) { //先定义一个已有前两项的数组,用来作缓存 var arr = [1 ...

  3. 算法与数据结构(九) 查找表的顺序查找、折半查找、插值查找以及Fibonacci查找

    今天这篇博客就聊聊几种常见的查找算法,当然本篇博客只是涉及了部分查找算法,接下来的几篇博客中都将会介绍关于查找的相关内容.本篇博客主要介绍查找表的顺序查找.折半查找.插值查找以及Fibonacci查找 ...

  4. #26 fibonacci seqs

    Difficulty: Easy Topic: Fibonacci seqs Write a function which returns the first X fibonacci numbers. ...

  5. 关于java的递归写法,经典的Fibonacci数的问题

    经典的Fibonacci数的问题 主要想展示一下迭代与递归,以及尾递归的三种写法,以及他们各自的时间性能. public class Fibonacci { /*迭代*/ public static ...

  6. POJ3070 Fibonacci[矩阵乘法]

    Fibonacci Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 13677   Accepted: 9697 Descri ...

  7. 算法系列:Fibonacci

    Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...

  8. 【Scala】尾递归优化

    以递归方式思考 递归通过灵巧的函数定义,告诉计算机做什么.在函数式编程中,随处可见递归思想的运用.下面给出几个递归函数的例子: object RecursiveExample extends App{ ...

  9. Fibonacci 2

    Fibonacci 2 感谢613的提供的题面 题目描述 给定\(S_0,S_1\),\(S_n=S_{n-1}+S_{n-2}+F_nF_{n-1}\),求\(S_n\bmod 2^{32}\). ...

随机推荐

  1. jquery 追加元素的方法(append prepend after before 的区别)

    append() 方法在被选元素的结尾插入内容. prepend() 方法在被选元素的开头插入内容. after() 方法在被选元素之后插入内容. before() 方法在被选元素之前插入内容. &l ...

  2. 【Git】Git SSH Key 生成步骤

    Git是分布式的代码管理工具,远程的代码管理是基于SSH的,所以要使用远程的Git则需要SSH的配置. github的SSH配置如下: 一 . 设置Git的user name和email: $ git ...

  3. 【调试】如何使用javascript的debugger命令进行调试(重要)

    首先安装firebug,在firefox的扩展里搜索安装即可. 然后在页面中启用firebug中的脚本: 然后在网页某些位置加入debugger命令,比如如下页面代码: <!DOCTYPE ht ...

  4. request.getScheme()的使用方法

    今天在修改bug时,发现程序使用了 request.getScheme() .不明白是什么意思,在google 搜索了一下.现在明白了.整理如下: 1.request.getScheme() 返回当前 ...

  5. Profile 的翻译

    最近要翻译一个英文网站的单词,正宗的英文网站总是有很多单词让我烦恼,这就是其中一个. 特地转一篇文章,对我大有帮助. 计算机中常用的 Profile 该如何理解? 我认为 Profile 即可作名词又 ...

  6. Codeforces538F A Heap of Heaps(函数式线段树)

    题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么就是一个违规点,统计出1~n-1完全叉树下的违规点的各自的个数. 一个直觉的思想就是暴力, ...

  7. MySQL -MMM 学习整理

    一. 规划 1.主机规划 服务器 IP 作用 monitor 10.0.0.10 监控服务器 master-01 10.0.0.5 读写主机01 master-02 10.0.0.6 读写主机02 s ...

  8. springBoot Ribbon Hystrix

    1.依赖包引入 <!-- 引入关于 hystrix的依赖 --> <dependency> <groupId>org.springframework.cloud&l ...

  9. 达梦数据库CAST与ROUND函数

    https://blog.csdn.net/zry1266/article/details/50856260

  10. iOS手势UIGestureRecognizer的使用失效问题

    问题:视图正常展示在界面中,父层是放在window上的,底部的一个控件的点击事件失效(所有设置都正常) 解决思路:虽然视图能够正常展示,但是发现父类视图的底部尺寸比子类的视图的尺寸小,也就是说上层视图 ...