剑指offer-09:递归和循环,斐波那契数列
2017-08-08 11:51
387 查看
当需要重复的计算相同问题时,通常可用递归或者循环迭代两种办法。
如计算1+2+…+N问题。
两种都可以做。递归代码简洁,但开销大,并可能导致栈溢出。当N=10000时递归不能正常运行,但循环可以。另外递归把问题分解为子问题求解,子问题间可能有重叠部分,就会存在重复计算。
计算斐波那契数列的第n项。
f(n) =
0, n=0;
1, n = 1;
f(n-1)+f(n-2), n>1
根据其定义非常清晰的写出其递归代码:
这说明要玩好递归,必须找到子问题,能像上面那样写出来,递归就没问题。
n试着输个10,结果是55。试着输个100,用秒的时间来等。效率太差!包含大量重复问题。算f(9)会算f(8)和f(7),算f(8)会算f(7)和f(6)。
递归看着很牛逼,但谁用谁知道。有没有实用的方法?当然,想想人是怎么计算递归的?不就是从头开始加到N吗?时间复杂度O(n)。
这当然不是最快的。并没有发挥数学的作用。数学的厉害之处在于从1加到N问题中像小高斯1分钟就算完的题目那样高效率。
同样的,斐波那契数列有数学上的归纳法计算公式:
[f(n)f(n−1)f(n−1)f(n−2)]=[1110]n−1
这说明只要计算出右边矩阵的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(n−1)和f(n−2)。则n>2时:
f(n)=f(n−1)+f(n−2)
这就是个斐波那契数列。
若青蛙一次可以跳1级,也可2级,…,也可n级,多少种?
答:问题抽象为:
f(n)=f(n−1)+f(n−2)+...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)=2n−1
用2*1的小矩形横着或者竖着填充大矩形。用8个2*1的小矩形无重叠的填充2*8的大矩形,总共多少种填法?
![](https://img-blog.csdn.net/20170808130424231?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbmlhb2xpYW5qaXVsaW4=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
答:
将覆盖问题记为f(8)。
当横着填时(红线),下方必须横,右边还剩f(6)
当竖着填时(蓝线),右边还剩f(7)
则f(8)=f(7)+f(6)。为斐波那契数列。
如计算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 ; 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(n−1)f(n−1)f(n−2)]=[1110]n−1
这说明只要计算出右边矩阵的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(n−1)和f(n−2)。则n>2时:
f(n)=f(n−1)+f(n−2)
这就是个斐波那契数列。
若青蛙一次可以跳1级,也可2级,…,也可n级,多少种?
答:问题抽象为:
f(n)=f(n−1)+f(n−2)+...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)=2n−1
用2*1的小矩形横着或者竖着填充大矩形。用8个2*1的小矩形无重叠的填充2*8的大矩形,总共多少种填法?
答:
将覆盖问题记为f(8)。
当横着填时(红线),下方必须横,右边还剩f(6)
当竖着填时(蓝线),右边还剩f(7)
则f(8)=f(7)+f(6)。为斐波那契数列。
相关文章推荐
- 【剑指offer】2.4.2递归和循环——面试题9:斐波那契数列
- 剑指offer:(7)递归和循环:斐波那契数列
- 【剑指offer】斐波那契数列--递归及循环剖析
- 剑指offer 2.4 递归和循环-斐波那契数列计算改进
- 【剑指offer】【斐波那契数列 】递归还是循环
- 剑指offer 07-10 斐波那契数列类型题目的动态规划解题方法(递归方法)
- 剑指offer 09:斐波那契数列
- 剑指offer----斐波那契数列的实现--递归和迭代
- 剑指offer_递归与循环---扑克牌顺子
- 剑指offer 算法 (递归与循环)
- 剑指offer--循环递归
- 【剑指offer-Java版】09斐波那契数列
- 剑指offer编程题——09 斐波那契数列以及相关问题
- 【剑指offer】递归循环两种方式反转链表
- 剑指offer-面试题09-斐波那契数列
- 剑指offer——树的镜像(基础,同样是考察遍历树的循环或递归)
- 【剑指offer】递归循环两种方式反转链表
- 剑指offer--斐波那契数列-递归
- 剑指offer_递归与循环---变态跳台阶
- (C++)剑指offer-8:跳台阶(递归和循环)