这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战
背景
学习前端三个月了,准备刷刷面试题,总结总结,一天几道面试题,向大厂进军。
问题
斐波那契数
计算斐波那契数
如斐波那契数,通常用F(n)表示,形成的序列成为 斐波那契数列。该数列由0和1开始,后面的每一项数字都是前面两项数字的和。也就是:
F(0)=0,F(1)=1, F(n)=F(n-1)+F(n-2),其中n>1。
给你n,计算F(n)
示例1:
输入: 2 输出: 1 解释: F(2)=F(1)+F(0)=1+0=1;
示例2:
输入: 3 输出: 2 解释: F(3)=F(2)+F(1)=1+1=2;
解析: 看到这里,大家是不是以为,这种题也太简单了吧,还搞个复杂的名字“斐波那契数”,分分种给它搞定,直接递归不就行了,于是有了下面的代码:
/**
* @param {number} n
* @return {number}
*/
var fib = function(n) {
return n <= 1 ? n : fib(n - 1) + fib(n - 2);
};
验证结果:
简单不简单,一行代码搞定了,难道就这样结束了,这公司是傻了吗?考这种题。
搞了半天,小丑竟是我自己。
来看看另外一种实现思路:动态规划-数组滚动
名字一听就比较高大上,我赶紧问问度娘这是啥意思!
动态规划有一个很重要的特点:无后效性,意思是当前状态的决策不受过去决策的影响。所以当状态很多时,我们不必去保存所有的状态,这样很占用内存,我们只需保存与当前决策有关的状态即可。
通俗易懂的意思就是节省内存,只保留必要的空间。
那我们再回过头来看看这道题:
- 条件边界是F(0)=0,F(1)=1。 当n>1时,f(n)=f(n-1)+f(n-2),相当于前两项的和。
- 根据这种理论,我们只需要数组遍历的时候,动态保存上两次的值,不就可以了吗?
图解:
来看看代码实现:
/**
* @param {number} n
* @return {number}
*/
var fib = function(n) {
if(n===0) return 0;
if(n===1) return 1;
//初始化默认值
//p=0 //F(-1)设置为0
//q=0 //F(0)=0
//r=1 F(1)的结果
var p=1,q=0,result=1;
for(let i=2;i<=n;i++){
p=q;
q=result;
result=p+q;
}
return result;
};
对比:第一种和第二种的方案
可以看到执行时间不同,第一种方案明显多执行了很多次数!
比如F(4)=f(3)+f(2);第一种方案:f(2)又重新计算了!
结语
一步一步慢慢来,踏踏实实把活干!