改善脑回路1——斐波那契数列

来源:互联网 发布:java接收post请求数据 编辑:程序博客网 时间:2024/06/07 11:41

笔者是一枚准备找工作的新手,为了准备一些算法思想,开启了改善脑回路计划。记录我思考问题的过程,如果能启发一下其他道友就更好了。标题原创,各位大大别乱用哈~

简介

斐波那契(Fibonacci)數列是一个非常简单的递归数列,除第一个和第二个数外,任意一个数都可由前两个数相加得到。形如:1, 1, 2, 3, 5, 8, 13…
要求就是:一个函数fibonacci(n),接受参数n为数列的长度,返回对象是长度为n的斐波那契数列

尝试

声明:程序用的是Python
第一步,写关键部分的代码。返回斐波那契数列中的数,基本规律是这一个数等于前两个数相加:result = late1 + late2。其中,三个数的顺序是...late1, late2, result...由此可见,返回斐波那契数列中的一个数需要前面两个数已知。所以,不仅要为返回值设置变量result,还要为计算值设置两个变量late1late2

def fib(n, late1, late2):    if n < 0:        '''报错'''    elif n == 0 or n == 1:        return 1    elif n >= 2:        result = late1 + late2        return result

问题来了:哪儿来的late1和late2以供计算呢,毕竟整体而言,只有一个输入参数,那就是n。**第二步,解决第一步剩余的相关问题。**late1和late2也是数列中的数,是之前计算的result,那么,在每次计算result的时候,我们都应该保留两个值(当前计算出的返回值及其前一个数)以供计算下一个result。

def fib(n, late1, late2):    if n < 0:        '''报错'''    elif n == 0:        return 0, 1    elif n == 1:        return 1, 1    elif n >= 2:        result = late1 + late2        return late2, resultdef fibonacci(n):    late, cur = 1, 1  # 初始当前值为1,前一个值为1    rslist = []  # 数列的存储列表    for i in range(n):        late, cur = fib(i, late, cur)        rslist.append(cur)    print rslist'''产生一个长度为10的fibonacci数列'''for x in fibonacci(10):    print x,# 输出为[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

第三步,对代码中的特殊情况特殊处理。要求输入的n必须为大于0的整数。在这里,先默认输入的都是整数,只对n<0的情况进行处理。n<0时,不返回值并且抛出参数异常。

def fib(n, late1, late2):    if n == 0:        return 0, 1    elif n == 1:        return 1, 1    elif n >= 2:        result = late1 + late2        return late2, resultdef fibonacci(n):    if n <= 0:        '''报错'''        print 'error'        raise ValueError, 'n must be an integer greater than zero!!'    late, cur = 1, 1  # 初始当前值为1,前一个值为1    rslist = []  # 数列的存储列表    for i in range(n):        late, cur = fib(i, late, cur)        rslist.append(cur)    return rslist

一般代码都有三个要求,基本要求是功能,进阶要求是效率,终极要求是可复用。到此我们已经完成了基本功能要求了,笔者当下心满意足,先去玩耍了~

加载中...

更新

最近看到别人写的一个更简单的方式, 如下:

def fib(n):    n, late, result = 0, 0, 1    rslist = []    while n < max:        rslist.append(result)        late, result = result, late + result        n = n + 1    return rslistdef fibonacci(n):    if n <= 0:        '''报错'''        print 'error'        raise ValueError, 'n must be an integer greater than zero!!'    else:        return fib(n)
具体改进的关键点有三个:
我们的代码中需要存储当前返回值和它之前的值。斐波那契数列第一个数是1, 它前面并没有其他数了,但是,因为我们只是用存储的两个数进行相加来计算返回值,所以,可以将第零个数设为0。
当输入为2时,函数需要返回[1, 1]。计算时, 第二个数通过上面的方法,计算为result = late1 + late2 = 0 + 1。但是第一个数的计算怎么办?可以采用先保存结果在计算的方式(跟篱笆桩的情况不太一样),虽然最后会多算一个多余值,不过无伤大雅。
现在fib()函数的参数只要一个。两个函数的结构稍作了改变。

更新2

如果因为输入n特别大,可能导致输出的列表特别大,造成内存溢出。为了控制存储空间,我们应该将输出的列表用generator生成器来表示
举个生成器和普通可迭代对象(list)的列子:

iter_list = range(10)  # 普通可迭代对象gene_list = xrange(10)  # 生成器print type(iter_list)print type(gene_list)for i in iter_list:    print i,for i in gene_list:    print i,print print iter_listprint gene_list---输出↓↓↓---<type 'list'><type 'xrange'>0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]xrange(10)

可以看出:

  1. 生成器和普通迭代器的效果是一样的
  2. 但是他们的直接打印结果不一样,是因为普通迭代器是先产生了整个数组并保存在内存中;而生成器只是一个生成数据的方式,当有需要的时候才会产生下一个值,因此也更省内存空间。

用一个生成器来实现斐波那契额数列:

class Fab(object):    def __init__(self, max):        self.max = max        self.n, self.a, self.b = 0, 0, 1    def __iter__(self):        return self    def next(self):        if self.n < self.max:            r = self.b            self.a, self.b = self.b, self.a + self.b            self.n = self.n + 1            return r        raise StopIteration()

或者是利用Python的yield命令:

# 简介版,使用yielddef fab(max):    n, a, b = 0, 0, 1    while n < max:        yield b        a, b = b, a + b        n = n + 1

结果都是一样的:

for n in fab(10):    print n,---输出↓↓↓---1 1 2 3 5 8 13 21 34 55

在 for 循环执行时,每次循环都会执行 fab 函数内部的代码,执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。

1 0
原创粉丝点击