【算法趣题】Q11 斐波那契数列

浏览: 1813

引言

【算法趣题】是来自图灵程序设计丛书绝云译的《程序员的算法趣题》,书中是用Ruby实现的。这里是用python来实现。

问题描述

斐波那契数列:又称黄金分割数列、因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:1、1、2、3、5、8、13、21、34、……

在数学上,斐波纳契数列以如下递归的方法定义:

image.png

计算这个数列中相邻两个数的商值,可以得到如表所示的结果。

1÷1     = 1.00000
2÷1     = 2.00000
3÷2     = 1.50000
5÷3     = 1.66667
8÷5     = 1.60000
13÷8   = 1.62500
21÷13 = 1.61538
34÷21 = 1.61905
55÷34 = 1.61765
89÷55 = 1.61818

可以看到,商值最终慢慢地趋近1.618.这就是有名的“黄金分割”的由来。

如下图所示,用斐波那契数列中的每个数除以数位上的数字之和。请继续例中的计算,求出后续5个最小的能整除的数。

2     →  2 ÷ 2

3     →  3 ÷ 3

5     →  5 ÷ 5

8     →  8 ÷ 8

21   →  21 ÷ 3 ... 2+1=3,因而除以3

144 →  144 ÷ 9 ...1+4+4=9,因而除以9

思路

我们先来定义一个函数,该函数有一个参数n,n为整数,表示整数n是否能被该整数数位上的数字之后整除。

def if_div(n):
length = len(str(n)) # 该整数共几位数
sum = 0
# 将各个位数上的数相加
for i in range(length):
sum = int(str(n)[i]) + sum
if(n % sum ==0): # 如果整除,返回True
return True
return False

image.png

不采用的方式

按照斐波那契数列的定义,我们可以写出斐波那契数列中第n个值的函数

def fib(n):
if n==0 or n==1:
return 1
else:
return fib(n-2) + fib(n-1)

image.png

如果我们直接按题意,依次遍历斐波那契数列,直到拿到我们所需要11个数为止,而数列中的每一个数都有函数fib(n)计算出来。即

import time
begin = time.time()
print("------计算开始-----") 
count = 0
n = 2
while(count<8):   
    value = fib(n)
    if if_div(value):
        count = count + 1
        print(str(count)+': '+ str(value))
    n = n + 1
end = time.time()
print("------计算结束-----")
print("耗时"+str(float(end-begin)))

image.png

注意到,我只拿到符合题意的8个数,就已经耗时15秒了,第9个数,耗时就很长了,我曾经花了1天时间都没结果出来,第10个数就更不用说了。

这说明了一个什么问题?

递归可能更容易理解,但程序的性能上不具优势,尤其当递归层次深时。

优雅方式

往往可以用递归方式的,基本上有更优的方式。

a,b,c是斐波那契数列中的连续3个数,根据定义则有a+b=c, 下一个连续3个数依然是a,b,c,只不过这时的a是前一个的b,这时的b是前一个的a,而这时的c是这时的a+b的和,依次往下。

import time
begin = time.time()
print("------计算开始-----")
a = b = 1
count = 0
while(count < 11):
c = a + b
if if_div(c):
count = count + 1
print(str(count)+': '+ str(c))
a, b = b, c
end = time.time()
print("------计算结束-----")
print("耗时"+str(float(end-begin)))

image.png

非常快,2毫秒就给出答案了。

推荐 1
本文由 _缘君_ 创作,采用 知识共享署名-相同方式共享 3.0 中国大陆许可协议 进行许可。
转载、引用前需联系作者,并署名作者且注明文章出处。
本站文章版权归原作者及原出处所有 。内容为作者个人观点, 并不代表本站赞同其观点和对其真实性负责。本站是一个个人学习交流的平台,并不用于任何商业目的,如果有任何问题,请及时联系我们,我们将根据著作权人的要求,立即更正或者删除有关内容。本站拥有对此声明的最终解释权。

2 个评论

改名了呀
哈,简短点了。

要回复文章请先登录注册