5.递归(学习笔记)

2.5.1递归的简介

    递归是有两个过程,去的过程叫递,回来的过程叫归,基本上所有的递归问题都可以用递推公式来表示,比如说,在电影院坐着想要知道自己在第几排,太黑了啥都看不清,可以问前面的人,自己只要加一就可以了,前面的也看不清,再问前面的......第一排总该知道吧,最终可以用公式:

f(n) = f(n-1)+1其中f(1)=1

递归需要满足的三个条件:

1.一个问题可以分解为几个子问题的解

    比如自己在第几排,可以分解为前面的人在哪一排这样的子问题。

2.这个问题与分解之后的子问题,除了数据规模不一样,解题思路完全相同

    前面一排人,想求解自己在哪一排的思路和我想求解的思路完全相同。

3.存在递归终止条件

    把问题拆解为子问题,子问题拆解为子子问题,一层层的分解下去,不能无限循环,需要一个终止条件,也就是第一排不需要在询问任何人,这就是终止条件。

2.5.2如何写递归代码

关键是写出递推公式,找到终止条件

    举一个例子:假设有n个台阶,可以一次走两个或者走一个,一共有几种走法,走上去。实际上,可以大体分为两类,一种是第一步走两个台阶,一种是第一次走一个台阶,所以n个台阶的走法等于走一步后n-1个台阶的走法,加上走两步后,n-2个台阶的走法,即f(n) = f(n-1)+f(n-2)。那么终止条件是什么,是当n=1时等于1,测试一下,n=2时,结果f(2)=f(1)+f(0),无法求解,所以可以把f(2)=2也做为终止条件,实现即为:

2.5.3递归代码要注意的问题

①递归代码要警惕堆栈溢出

    比如前面讲到的电影院的例子,如果我们将jvm的堆栈大小设置为1KB,那么在求解count(19999)时就会报错,Exception in thread "main" java.lang.StackOverflowError,所以在递归时要考虑最大深度来解决这个问题,比如说在1000以后,就抛出一个异常,不再继续往下递归了。一般在最大深度比较小时才会考虑这种方法。

②递归代码要警惕重复运算

    如图:如果想要计算f(6),那么要计算f(4)和f(5),而要计算f(5)又要计算f(3)和f(4),这样f(4)就被计算了多次,为了避免重复计算,可以通过一个数据结构(比如散列表)来保存已经求解过的f(k),如果已经求解过了,直接从散列表中取出,来避免进行重复计算。

③递归的利弊

    递归有利有弊,递归代码表达力很强,写起来很方便,但是不利的一面就是空间复杂度高,有堆栈溢出的风险。

(本文是个人听课笔记,不少东西摘取于王争老师的原文,原文链接http://gk.link/a/10aMZ)

你可能感兴趣的:(5.递归(学习笔记))