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

题目

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+...+2n2=2n2

时间复杂度: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(n1)]=[1110][f(n1)f(n2)]

我们通过不断迭代,很显然能得出公式:
[f(n)f(n1)]=[1110]n2[f(2)f(1)]

所以要求f(n),只需要求出矩阵
[1110]n2

的值就行了。

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

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

A6=A3A3

A7=A3A3A1=A4A2A1

在这里,我们可以类似地把A看做是二进制中的2, 27=242221 也就是说可以把矩阵的幂转换成二进制来表示。从而可以将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编程和活动脑筋的目的,还是决定每个星期研究个一个来玩玩。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值