剑指offer-09:递归和循环,斐波那契数列

当需要重复的计算相同问题时,通常可用递归或者循环迭代两种办法。

如计算1+2+…+N问题。

// 递归实现
int add1toN_recursive(int n)
{
    return n <= 0 ? 0 : (n + add1toN_recursive(n-1));
}
// 循环实现
int add1toN_Iterative(int n)
{
    int result = 0;
    for(int i = 0; i<n; ++i)
        result += i;

    return result;
}

两种都可以做。递归代码简洁,但开销大,并可能导致栈溢出。当N=10000时递归不能正常运行,但循环可以。另外递归把问题分解为子问题求解,子问题间可能有重叠部分,就会存在重复计算。


计算斐波那契数列的第n项。
f(n) =
0, n=0;
1, n = 1;
f(n-1)+f(n-2), n>1

根据其定义非常清晰的写出其递归代码:

long long Fibonacci(unsigned int n)
{
    if(n <= 0)
        return 0;
    if(n == 1)
        return 1;

    return Fibonacci(n-1) + Fibonacci(n-2);
}

这说明要玩好递归,必须找到子问题,能像上面那样写出来,递归就没问题。

n试着输个10,结果是55。试着输个100,用秒的时间来等。效率太差!包含大量重复问题。算f(9)会算f(8)和f(7),算f(8)会算f(7)和f(6)。


递归看着很牛逼,但谁用谁知道。有没有实用的方法?当然,想想人是怎么计算递归的?不就是从头开始加到N吗?时间复杂度 O(n)


long long Fibonacci_ite(unsigned int n)
{
    // 第1项和第2项,直接返回值
    int result[2] = {0, 1};
    if(n < 2)
        return result[n];

    long long fib_1 = 0;
    long long fib_2 = 1;
    long long fib_n = 0;
    // 从第3项开始迭代往后求
    for(unsigned int i = 2; i <= n; ++i)
    {
        fib_n = fib_1 + fib_2;
        // 更新本次值以备下次
        fib_1 = fib_2;
        fib_2 = fib_n;
    }

    return fib_n;
}

这当然不是最快的。并没有发挥数学的作用。数学的厉害之处在于从1加到N问题中像小高斯1分钟就算完的题目那样高效率。

同样的,斐波那契数列有数学上的归纳法计算公式:

[f(n)f(n1)f(n1)f(n2)]=[1110]n1

这说明只要计算出右边矩阵的n-1次方,则第一项为f(n)的值。如果简单从0开始循环乘方,时间复杂度仍为 O(n)

然而乘方可以用平方来计算。要算4次方,则只需要算出2次方,再平方即可。这样时间复杂度减至 O(logn)

但是隐含的时间常数巨大,代码复杂,实际中不太使用。仅做知识面展示。

实现链接:http://blog.csdn.net/dadoneo/article/details/6776272


斐波那契数列可以加上很多应用场景。

  • 例1:一只青蛙一次可以跳上1级台阶,也可跳上2级台阶,求跳上n级台阶总共有多少种跳法?

答:
若只有1级,则1种;若有2级,则2种跳法。
把n级台阶的跳法看成n的函数f(n)。当n大于2时,因为第一次可2种跳法,则分两种情况。每种情况下的子问题分别是 f(n1) f(n2) 。则n>2时:

f(n)=f(n1)+f(n2)

这就是个斐波那契数列。


  • 若青蛙一次可以跳1级,也可2级,…,也可n级,多少种?

答:问题抽象为:

f(n)=f(n1)+f(n2)+...f(1)+f(0)f(1)=1,f(0)=1

f(0)=1f(1)=1f(2)=1+1=2f(3)=2+1+1=4f(4)=4+2+1+1=8f(5)=8+4+2+1+1=16...f(n)=2n1


  • 用2*1的小矩形横着或者竖着填充大矩形。用8个2*1的小矩形无重叠的填充2*8的大矩形,总共多少种填法?

这里写图片描述

答:

将覆盖问题记为f(8)。

当横着填时(红线),下方必须横,右边还剩f(6)
当竖着填时(蓝线),右边还剩f(7)

则f(8)=f(7)+f(6)。为斐波那契数列。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值