《剑指offer》面试题10:题目1斐波那契数列(C++实现)
《剑指offer》面试题10:题目1斐波那契数列(C++实现)
题目描述
要求输入一个n,输出斐波纳妾数列的第n项。n<=39
斐波那契数列定义如下。
f(n)={0n=01n=1f(n−1)+f(n−2)n>1 f(n)=\left\{ \begin{aligned} 0&&\text{n=0} \\ 1&& \text{n=1}\\ f(n-1)+f(n-2)&& \text{n>1} \\ \end{aligned} \right. f(n)=⎩⎪⎨⎪⎧01f(n−1)+f(n−2)n=0n=1n>1
思路一:简单的递归
在我们刚刚入门的时候,几乎在所有的C语言书上,都会介绍斐波那契数列。
所以我们很快能写出如下的代码:
//运行时间:880ms //占用内存:504K class Solution { public: int Fibonacci(int n) { if(n<=0) return 0; if(n==1||n==2) return 1;//这里要加上或者n=2才能在牛课上提交出结果,否则就是超时 return Fibonacci(n-1)+Fibonacci(n-2); } };
很好,说明你还记得以前学的东西。但是我们现在是要马上去面试的人了,怎么能写这么low的代码呢?
说它low是因为上述的代码有很严重的递归问题,比如求解f(10),你需要求解f(9)和f(8)。而求解f(9),你又需要去求解f(8)和f(7)。
说到这里,你会发现上面的f(8)咱们就求解了两遍!如果是一个特别大的数字,那么重复求解的问题会呈指数级的急剧增加,所以我们得想个法子,把这个重复求解的问题把它解决了!
思路二:用数组记录f(n)
最简单的思路,就是用一个数组来记录下我们的f(n),每次计算f(n)前,我们先查询这个值是否计算过,如果没有,就执行递归调用计算它,并把它存储下来,下次直接调用就可以了。
如果有,那就更好了,咱们不用客气,直接拿来用,这样就省去了很多重复求解的问题。
//运行时间:3ms //占用内存:480K class Solution { public: int memo[40]={-1}; int Fibonacci(int n) { memo[0] = 0; memo[1] = 1; for(int i=2;i<=n;i++) memo[i]=memo[i-1]+memo[i-2]; return memo[n]; } };
思路三:自底向上计算(动态规划)
既然可以用递归实现,我们自然可以想到用动态规划去实现。
首先根据f(0)和f(1)去推算f(2),再根据f(1)和f(2)去推算f(3),依次类推,直到推算出我们要求的f(n),再把这个值返回即可。
//运行时间:4ms //占用内存:480K class Solution { public: int Fibonacci(int n) { if(n<=0) return 0; if(n==1||n==2) return 1; int FibMinusTwo = 0;//定义f(n-1) int FibMinusOne = 1;//定义f(n-1) int FibN= 0; for(int i=2;i<=n;i++){ FibN = FibMinusOne + FibMinusTwo;//f[i]=f[i-1]+f[i-2]; FibMinusTwo = FibMinusOne;//更新f[i-2]; FibMinusOne = FibN;//更新f[i-1]; } return FibN; } };
相对于思路二而言,思路三更加节省空间。
小结
思路一代码会有很多重复计算的地方,不太可靠。
思路二应用了memo来记录,避免了思路一里面很多重复计算的地方。
思路三相对于思路二而言,在占用内存上又有了更好的优化。
整体而言,思路三最佳。
参考文献
《剑指offer》
牛课网刷题链接link.
- 《剑指offer》面试题10:题目3青蛙变态跳台阶(C++实现)
- 《剑指offer》面试题10:题目4矩形覆盖(C++实现)
- 《剑指offer》面试题10:题目2跳台阶(C++实现)
- 剑指offer面试题10:斐波那契数列(Java 实现)
- 《剑指offer》面试题22:链表中导数第K个节点(C++实现)
- 《剑指offer》面试题29:顺时针打印矩阵(C++实现)
- 《剑指offer》面试题57 删除链表中重复的结点 C++ 实现 以及 错误总结 (指针问题)!!
- 剑指offer面试题10 二进制中1的个数 java实现
- 《剑指offer》面试题16:数值的整数次方(C++实现)
- 剑指Offer面试题10:斐波那契数列
- 剑指offer:面试题10—斐波那契数列+青蛙跳台阶
- 《剑指offer》面试题25:合并两个排序的链表(C++实现)
- 剑指offer 面试题2 Singleton模式 C++实现
- 剑指offer 面试题10 斐波那契数列
- C++笔试题(剑指offer 面试题7 两个栈实现队列)
- 剑指offer(面试题50)树中两结点的最低公共祖先(C++实现)
- 剑指Offer(第二版)面试题10:斐波那契数列
- 《剑指offer》面试题10:斐波那契数列(含矩阵乘法解法)
- 《剑指offer》面试题4:二维数组的查找(C++实现)
- 剑指Offer---面试题:使用两个栈实现队列