Swift来解决斐波那契数列

709 阅读3分钟

现在作为一个程序员,或多多少都需要会一些算法的,毕竟面试造火箭的时候,他还是很有用的。还记得当时面试的时候,领导问完iOS相关的问题之后,就开始问了一个很经典的算法题:斐波那契数列

斐波那契数列就是后面一个数的和是前面两个数的和相加
a(0) = 1,
a(1) = 1,
a(2) = 2,
...
a(n) = a(n-1) + a(n-2), n>=2;

当时的第一想法就是,递归呀,然后领导很细心的递上了他的mac(😊,看来只动嘴还是不行)。然后我内心很不情愿的接过来他的mac。直接playground开干,噼里啪啦,一顿干。信心满满的给了领导。但是转头一看,领导咋这一脸嫌弃的表情啊。就是这么干呀。大家觉得我这么做对吗?

import UIKit

func fb(_ num: Int) -> Int {
    if num < 3 {
        return 1
    } else {
        return fb(num - 1) + fb(num - 2)
    }
}

print(fb(10))

领导皱着眉头说,你算一下2017这个数看看,我立马print(2017).接下来几分钟相当尴尬。控制台估计睡着了,啥也不干。

就看到右边的计算次数在不断的增加。当时有点尴尬。但是领导很有耐心地说,你这么做是能算出来简单的斐波那契数。但是越到后面越算越吃力。你思考一下你这么算的时间复杂度。

递归计算时间复杂度就是用子问题个数乘以解决一个字问题需要的时间。
子问题个数就是递归树重的节点总数。递归树就是个二叉树。二叉树的节点总数是指数级别的,所以子问题的个数为O(2^n).
解决一个问题需要的时间比较简单,fb = fb(num - 1) + fb(num - 2). 时间为0(1)
所以这种方式的时间复杂度为O(2^n).
fb(2017),这个简直爆炸了。

还好领导没有直接放弃,换了一种方式引导我。你这么做,重复计算太多了,有没有办法,去掉不必要的重复计算。我仔细一想,是的哦。如果我能把上次的两个值先保存下来,下次直接去取不就好了吗? func fb(_ num: Int) -> Int {

var arr: [Int] = [1,1]

if num < 2 {
    return arr[num - 1]
}

let index = num - 1

for i in 2...index where index > 2 {
    arr.append( arr[i - 1] + arr[i - 2] )
}

    return arr[num - 1]
}
print(fb(50))

这样一来,自然就减少了很多不必要的计算。很容易就能算出结果了。 然后我们领导笑了笑,如果不允许创建数组,你有办法吗? 当然可以啊,我笑着说。弄两个临时变量。一个是左边的left,一个是左边的左边的left,每次记录着两个值,替换着两个值,到最后的结果就是这两个的和。然后就和谐的面试结束了,代码都没要我写。😁。但是在这里,我还是写一下,给大家分享一下。

 func fb(_ n:Int) -> Int {
     if n < 3 {
         return 1
     }

     var left = 1, preLeft = 1

    for _ in 3...n {
        let sum = left + preLeft
        preLeft = left
        left = sum
    }
 
    return left
}

我的思路就是这样的,希望能对大家有所帮助。