算法设计+剑指习题——递归

一、什么是递归?

	递归是一个奇妙的现象,书上的解释是在函数的定义中又调用
	函数自身。举个例子就是你想要零花钱需要问爸爸妈妈,当你
	问妈妈时,她说没有钱,问你爸要去,他有私房钱,于是你转
	头向爸爸要,爸爸却说家里钱都在妈妈手里,去向妈妈要……
	这就是无限递归(如果要编写递归函数时需要注意有终止条件
	,否则你就永远要不到钱了,哈哈)。
	我直接用我自己或者我间接用我自己都是递归。
	那什么时候用到递归呢?

那什么时候用到递归呢?

  • 定义是递归
    这种类型我们需要特别了解的就是Fibonacci数列,在后面的习题当中我们会以它为原型遇到多次!!
  • 数据结构是递归
    我们要设计算法就是为了方便处理数据,而最重要的数据结构也可以用递归设计比如单链表
  • 问题求解方法是递归
    这个最著名的Hanoi问题他的求解方法就是利用递归的思想

那递归的思想是什么呢?
分解:把大问题转化成一个或几个的小问题,把小问题转化成更小的问题,直到小问题都可以解决。就像你做数学题,我要求一个难题先看解决这个难题我需要什么,要求几块小内容,然后再看这几个小内容又分别要求什么,最后看看我已知条件里有没有我需要的。
求值:将已知的小问题计算大问题

这时候你会问了:我知道了递归的思想那递归又是怎么执行的呢?我想更加深入看看递归的运行机制!!
在我看过的递归的资料当中,我认为刘汝佳老师讲的是最适合我去理解的(推荐给大家哟!)
首先我们需要知道的是系统每一次调用都要开辟一组存储单元,用来存放本次调用的返回地址以及被中断的函数参数值(即一个栈帧):也就是说,递归执行是通过系统栈来实现的。
这里不得不介绍刘老师讲的了:
很是可爱呀
很是可爱呀,这个例子哈哈

二、递归算法设计

其实一般遇到递归的问题都是先想到找关系,利用数学归纳法来求出递推关系式(也就是递归体),而我们在利用递归技术时,数学归纳法只是基础。
我们已经讲过递归的思想,其实这个自上而下分解,再自下而上求值是一种分而治之的算法设计方法。

三、递归算法设计示例

(1)单链表
在学习数据结构的时候我们一定写过这道题:
有一个不带头节点的单链表L,设计一个算法删除其中所有节点值为x的节点。

void Deletex(LinkNode *&L,ElemType x){
	LinkNode *p;
	if(L==NULL)
		return;
	if(L->data==x){
		p=L;
		L=L->next;
		free(p);
		Deletex(L,x);
	}
	else
		Deletex(L->next,x);
}
(2)八皇后问题【这个会有单独的博客讲述】

四、剑指offer——递归题

在这里插入图片描述
第一种解法:我向上跳一个台阶则剩下的方法是f(n-1),向上跳两个则是f(n-2),所以f(n)=f(n-1)+f(n-2),这便是上面我们讲的递归体

int jumpFloor(int number ) {
       if(number<=1)
           return 1;
        if(number==2)
            return 2;
        return jumpFloor(number-1)+jumpFloor(number-2);
}

第二种解法(也是推荐大家学习的设计思想):这种设计思想是将递归算法转化为非递归算法,下面这中解法是——用循环结构替代递归过程。
其中最为经典的就是采用循环结构求解Fibonacci的算法:

int Fibonacci(int n) {
	  int i,f1,f2,f3;
      if (n == 1|| n == 2) return 1;
      f1 = 1, f2 = 1;
      for (int i=3; i<=n; ++i) {
            f3 = f1 + f2;
            f1 = f2;
            f2 = f3;
        }
        return f3;
}

把上述算法思想用到这道题中就是如下解法:

int jumpFloor(int n) {
     if (n == 0 || n == 1) return n;
        int a = 1, b = 1, c;
        for (int i=2; i<=n; ++i) {
            c = a + b;
            a = b;
            b = c;
        }
        return c;
}

在这里插入图片描述
当我们用一个12覆盖最左边的一个,则剩下的2(n-1)方格有f(n-1);如果用两个的话则有f(n-2)种,忽然发现这不又是斐波那契嘛!于是上代码!

int rectCover(int n) {
    if (n==0 || n==1 || n==2) return n;
    int a = 1, b = 2, c;
    for (int i=3; i<=n; ++i) {
        c = a + b;
        a = b;
        b = c;
    }
    return c;
}

那为什么要用这种循环结构来代替呢?
原因是递归算法运行时间长、效率低、还占用空间,有溢出的风险,上述两道题的递归体解法:
时间复杂度:O(2^n)
空间复杂度:递归栈的空间
而循环体解法:
时间复杂度:O(n)
空间复杂度:O(1)
哪个效率更高一目了然哟~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绵绵羊23333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值