青蛙跳

斐波那契 数列变形

做到一个有意思的题:

一只青蛙一次可以跳上1级台阶,也可以跳上2级,该青蛙跳上一个n级的台阶总共有多少种跳法?

首先来理一下思路,做几个假设先:

找规律

从上图是不是可以看出些什么?当n=1时,跳法为1种,n=2时跳法为2种,n>2时,我们可以把n级台阶的跳法不同总数看成是n的函数f(n),f(n)=f(n-1)+f(n-2)

关键思想

这个实质上就是斐波那契数列的简单变形,不知道斐波那契是什么的小伙伴可以移步至文首点击链接。

看到以上数学公式马上可以想到最简单的一种写法来解决这个问题:

  • 方法一:递归
function fib(n) {
    return n < 3 ? n : (fib(n - 1) + fib(n - 2))
}

结果如下

递归写法结果

优点:代码简洁易懂
缺点:重复运算导致运算量太大,效率极其低下,损耗性能,递归的次数太多时就会超出栈的容量导致调用栈溢出,而栈溢出可能导致计算出错误的数据,不推荐!!!

既然递归的方法不可取,那有没有更高效的办法呢?
如果我们将计算过的斐波那契数存入数组中,那么当要计算一个斐波那契数时只需要通过下标的方式找到它前两个数字相加就可以了

  • 方法二:循环
function fib(n) {
    var temp = []
    if (n == 1 || n == 2) {
        return n
    } else {
        temp[1] = 1
        temp[2] = 2
        for (var i = 3; i <= n; i++) {
            temp[i] = temp[i - 1] + temp[i - 2]
        }
        return temp[i - 1]
    }
}

结果如下:

循环写法结果

优点:效率高,避免重复计算,传入n=1000,只需要1ms就出现结果
缺点:循环写法用空间换时间,如果n足够大我们则需要开辟足够大的内存空间用来存储这个数组,也不是很可取

是不是可以不用存储所有的斐波那契数,只需要把我们要求的前两个斐波那契存储下来就可以了呢?答案是肯定的

  • 方法三:定义临时变量
function fib(n) {
    var num1 = 1, num2 = 1, num3 = 1
    for (var i = 2; i <= n; i++) {
        num3 = num1 + num2
        num1 = num2
        num2 = num3
    }
    return num3
}

结果如下:

定义临时变量写法结果

优点:与循环写法一样,效率高,且只用存储前两个变量,省内存,省时间,可以说是非常完美了。

如果说不让使用临时变量呢,有这么苛刻的人吗?可是万一有呢【手动滑稽】
有也可以解决的啦~

  • 方法四:一加一减解决问题
function fib(n) {
    var num1 = 1, num2 = 1
    for (var i = 2; i <= n; i++) {
        num1 = num1 + num2
        num2 = num1 - num2
    }
    return num1
}

结果如下:

一加一减

细心的你会发现,诶,为什么同样传入的n值为500,为什么前面得到的结果是2.2559151616193602e+104,而现在得到的却是2.2559151616193665e+104呢?

这就要说到浏览器计算的精度问题了,由于计算机是用二进制来存储和处理数字,无法精确表示浮点数,连自身都不能精确,运算起来就更加得不到精确的结果了,因此这种精度差异几乎出现在所有的编程语言中(例如C/C++/C#,Java),准确的说:“使用了IEEE 754浮点数格式”来存储浮点类型(float 32,double 64)的任何编程语言都有这个问题,而C#、Java是因为提供了封装类decimal、BigDecimal来进行相应的处理才避开了这个精度差异。而javascript是一种弱类型的脚本语言,本身并没有对计算精度做相应的处理。

举个简单的栗子:

精度测试

值越大误差越大,当计数变为科学计数法后,运算一次就有一次误差,上例中,加法一次误差,减法一次误差,导致最后呈现出的结果有些不一样,而实际的结果却没有问题,看以下在ruby中测试的结果~

n=500时ruby中的结果

以上结果测试的是n=500时方法三和方法四给的结果
可以看出,在不用科学计数法表示数字的情况下,精度就可以得到保证了,而我想知道的只是第四种方法得到的结果有没有问题,答案是没有问题,可以放心使用。

优点:非常完美,除了科学计数法表示的精度差别
缺点:值过大时得到的是科学计数法表示的结果,存在误差,n的值越大误差越大,然鹅实际结果是没有问题滴,可以大胆使用。

综上所述,还是推荐方法三,毕竟如果没有龟毛的人提出不准使用临时变量这种需求,它完全是完美的。

那么~来扩展一题:一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

首先还是穷举法:

找规律

虽然很蠢但这种找规律的方法很快呀
代码如下

function fibBT(n){
    return Math.pow(2,n-1)
}

结果如下:效率也是非常高呢

变态跳结果

做完后我在网上看了很多关于变态跳的解法,几乎都是千篇一律说变态跳是斐波那契引申问题,分析过程繁杂且不清晰,字数太多我一时还没看明白,所以感觉不太满意,我的代码经自己多次测试没有发现问题,如果你有查到bug欢迎随时指正,一定虚心接受。

20171024补充一题

用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

本题依旧是斐波那契数列变形

凑合看看
//n=1,f(n)=1,n=2,f(n)=2,n>2,f(n)=f(n-1)+f(n-2)

function recFib(n) {
    var num1 = 0, num2 = 1, num3
    if (n >= 1) {
        for (var i = 0; i < n; i++) {
            num3 = num1 + num2
            num1 = num2
            num2 = num3
        }
        return num3
    }
}
console.log(recFib(1))//1
console.log(recFib(2))//2
console.log(recFib(3))//3
console.log(recFib(4))//5
console.log(recFib(5))//8
console.log(recFib(6))//13
console.log(recFib(7))//21
console.log(recFib(8))//34
console.log(recFib(9))//55
console.log(recFib(500))//2.2559151616193602e+104

推荐阅读

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 原文链接:http://blog.csdn.net/qq_22329521/article/details/529...
    越长越圆阅读 1,557评论 0 1
  • 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。解:1个台阶:12个台阶...
    MAXPUP阅读 382评论 0 0
  • 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上n级台阶一共有多少种方法?思路:假设1级台阶有f(1...
    江小修阅读 788评论 0 0
  • 大家好,我是144号星宝宝罗莉,正在参加小牛妈妈举办的第10期21天写作训练的蜕变之旅第20天,这是我第188篇原...
    罗文均阅读 112评论 0 1
  • 转眼特种兵的学习已经两周过去了,这种军事化的训练,比我想象中的难太多。第一次的训前作业就搞得我头晕脑胀喘不过气来的...
    冰雨_2bd4阅读 196评论 0 0