递归(斐波那契数列)

来源:互联网 发布:java整形转化为字符串 编辑:程序博客网 时间:2024/05/21 17:39
递归是一种极为常用的编程思想。比较官方的解释是“可以在函数内部,直接或间接地调用函数自身”,我一般把他称为“一种有技术含量的偷懒算法”。为什么这么说呢?因为递归函数不需要我们对运算过程的每一步的细节了解详细,而只需要我们知道两点:

1. 函数是如何“升级”的。也就是这一步需要解决的问题与其子问题之间的关系
2. 函数到什么位置“触底”,“触底”后返回什么?

看一个具体的例子:计算n!,当然,在数学上是这样计算的:n! = 1 x 2 x 3 x 4 x...x (n - 1) x n。我们可以这样观察:
1.  函数是如何“升级”的。也就是从 (n - 1)! 到 n! 是怎么做的呢: n! =  (n - 1)! x n
2. 函数到什么位置“触底”。显然,当 n = 1的时候,返回1


def fact(n):    # “触底”条件及反应    if n == 1:        return 1    # “升级”过程    return n * fact(n - 1)

所以,递归思想帮助我们用接近于自然语言的逻辑描述,完成了程序设计,是算法中非常重要的内容。此外,后面我们会接触到的“深度优先搜索”,“动态规划”也都借用了递归的基本原理,只是应用场景更加特殊罢了。

了解了递归,就可以完成斐波那契数列的构造了。斐波那契数列是说这样一个数列:[0, 1, 1, 2, 3, 5......],每个数都是数列中它的前两个数的和(2是1和1的和,3是1和2的和,......),而最前面两个数为0和1。

因此,现在要完成的任务,是写这样一个程序,给出一个索引n,返回斐波那契数列的第n个数。

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

当然,递归的效率是它的缺陷,所以在lintcode上做这道题时,需要用迭代的思想才能通过测试(有点类似于二叉树的遍历,递归很简单,面试时却需要用迭代):

def fib(n):    first, second = 0, 1    if n == 1:        return first    if n == 2:        return second    for i in range(2, n):        temp = first        first = second        second += temp    return result

题中,我用first和second两个指针指向构成新数的两个加数(也就是此时已存在数列的最后两个数)。
变的再有趣一点,能不能每次返回从1到n的一个斐波那契数列的全部呢?还是两种方法:

# 迭代返回列表def fib(n):    if n == 1:        return [0]    first, second = 0, 1    result = [0, 1]    for i in range(2, n):        temp = first + second        first = second        second = temp        result.append(temp)    return result# 递归返回列表def fib(n):    if n == 1:        return [0]    if n == 2:        return [0, 1]    return fib(n - 1) + [fib(n - 1)[-1] + fib(n - 1)[-2]]

大家可以自己把上面的代码写出来感受一下。







0 0
原创粉丝点击