您的位置:首页 > 其它

算法一---斐波那契数列

2017-09-24 14:55 183 查看

题目

Question1 2017年9月17日

Description:

查找斐波纳契数列中第 N 个数。

所谓的斐波纳契数列是指:

前2个数是 0 和 1 。

第 i 个数是第 i-1 个数和第i-2 个数的和。

斐波纳契数列的前10个数字是:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34 …

分析

1.递归

根据题目描述就可以列出求斐波那契数列的公式:

f(n) = f(n-1) + f(n-2)


def fibonacci1(self, n):
if n == 1 or n == 2:
return n-1
else:
return self.fibonacci1(n-1) + self.fibonacci1(n-2)


分析一下,求第n个数要执行多少次?

要执行1+2+4+8+...+2n−2=2n−2次

时间复杂度:O(2N)

2.循环

当然按照公式,一开始我们就定义两个数,做一次n级的循环,每次循环给这两个数重新赋值,这样就能把执行次数维持在n的时间复杂度上:

def fibonacci2(self,n):
if n == 1 or n == 2:
return n-1
f1 = 0
f2 = 1
f3 = 1
i = 3
for i in range(i-1,n):
f3 = f2
f2 = f1 + f3
f1 = f3
re*turn f2


时间复杂度:O(N)

3.矩阵

仔细观察一下,其实斐波那契数列前后项的关系可以用矩阵相乘实现:

[f(n)f(n−1)]=[1110][f(n−1)f(n−2)]

我们通过不断迭代,很显然能得出公式:

[f(n)f(n−1)]=[1110]n−2[f(2)f(1)]

所以要求f(n),只需要求出矩阵

[1110]n−2

的值就行了。

计算二阶矩阵的N次幂运算,由于二阶矩阵乘法满足结合律,这样,可以快速计算二阶矩阵的n次幂运算。

假设A为一个二阶矩阵,则A的幂运算满足下面的条件:

A6=A3∗A3

A7=A3∗A3∗A1=A4∗A2∗A1

在这里,我们可以类似地把A看做是二进制中的2,27=24∗22∗21也就是说可以把矩阵的幂转换成二进制来表示。从而可以将n次幂拆解成长度为logn的二进制数来表示:7=111(二进制)。

这就是快速求二阶矩阵的核心方法。

def matrix(n):
base=[[1,1],[1,0]]  # 基础矩阵
ans=[[1,0],[0,1]]  # 结果矩阵
while n:
if n&1:  # 取n的二进制的最后一位和1做与运算,如果最后一位是1,则进入if体内部
ans=multi(ans,base)  # 如果在该位置n的二进制为1,则计算ans和base矩阵
base=multi(base,base)  # base矩阵相乘,相当于初始base矩阵的幂*2
n>>=1  # n的二进制往右移一位
return ans[0][1]  # 最后获取到的二阶矩阵的[0][1]即f(n)的值

def multi(a,b):  # 计算二阶矩阵的相乘
c=[[0,0],[0,0]]  # 定义一个空的二阶矩阵
for i in range(2):
for j in range(2):
for k in range(2):  # 新二阶矩阵的值计算
c[i][j]=a[i][k]*b[k][j]
return c


时间复杂度:O(logN)

总结

这个是Lintcode上的入门题,原本以为一个晚上就能写完的,结果发现从慢到快的算法研究弄了我好几天,最后的矩阵乘法也是网上看到的,毕竟数学荒废好多年了。正好新学了一点点python,虽然算法题对我现在的工作感觉没什么帮助,本着练手python编程和活动脑筋的目的,还是决定每个星期研究个一个来玩玩。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法