数据结构——递归

最近开始学习王争老师的《数据结构与算法之美》,通过总结再加上自己的思考的形式记录这门课程,文章主要作为学习历程的记录。

递归是一种非常高效、简洁的编码技巧,一种应用非常广泛的算法,比如DFS深度优先搜索、前中后序二叉树遍历等都是使用递归。基本上所有的递归问题都可以用递推公式来表示。以寻找电影排数为例,只需要问前一排人的排数,然后前一排的人再向前询问······用递推公式表示即为f(n)=f(n-1)+1,f(1)=1,将其改为递归代码,如下:

int f(int n){
    if (n==1) return 1;
    return f(n-1)+1;
}

递归需要满足的条件

遇到什么样的问题时可以运用递归呢?有三个条件需要满足:

1.一个问题的解可以分解为几个子问题的解,即将问题分解为数据规模更小的问题。

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

3.存在递归终止条件

以LeetCode第70题爬楼梯为例,假设你正在爬楼梯。需要 n 阶你才能到达楼顶。每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

实际上,可以根据第一步的走法将所有走法分为两类,第一类是第一步走了一个台阶,另一类是第一步走了两个台阶,用公式表示就是f(n)=f(n-1)+f(n-2),终止条件为f(1)=1,f(2)=2,此时,将其转化为代码为:

int f(int n){
    if (n==1) return 1
    if (n==2) return 2
    return f(n-1)+f(n-2)
}

写递归代码的关键就是找到如何将大问题分解为小问题的规律,并且基于此写递推公式,然后再推敲终止条件,最后将递推公式和终止条件翻译成代码。对于递归代码,若试图想清楚整个递和归的过程,实际上是进入了一个思维误区。
那该如何理解递归代码呢?如果一个问题A可以分解为若干个子问题B、C、D,你可以假设子问题B、C、D已经解决。而且,你只需要思考问题A与子问题B、C、D两层之间的关系即可,不需要一层层往下思考子问题与子子问题,子子问题与子子子问题之间的关系。屏蔽掉递归细节,这样子理解起来就简单多了。
因此,理解递归代码,就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑去分解递归的每个步骤。

递归常见问题

1.警惕堆栈溢出:递归调用超过一定深度(比如1000之后),就不再继续往下递归,直接返回报错,声明一个全局变量来控制递归的深度,从而避免堆栈溢出。
2.警惕重复计算:通过某种数据结构来保存已经求解过的值,从而避免重复计算。

除了堆栈溢出和重复计算这两个问题,递归代码还存在很大问题:在时间效率上,递归代码中多了很多函数调用,当数量较大时,就会积聚成一个可观的时间成本。在空间复杂度上,因为递归调用一次就会在内存栈中保存一次现场数据,所以在分析递归代码空间复杂度时,需要额外考虑这部分的开销。

如何将递归改写为非递归代码?

递归有利有弊,利是递归代码的表达力很强,写起来非常简洁;而弊就是存在许多问题,如空间复杂度高、有堆栈溢出的风险、存在重复计算、过多的函数调用会耗时较多等问题。所以,在开发过程中,我们要根据实际情况来选择是否需要用递归的方式来实现。

我们可以将递归代码转为非递归代码,以爬楼梯为例:

class Solution(object):
    def climbStairs(self, n):
        """
        :type n: int
        :rtype: int
        """
        if n == 1:
            return 1
        elif n == 2:
            return 2
        elif n>2:
            a,b = 1,2
            for i in range(2,n):
                a,b = b,a+b
            return b

当n大于2时,f(n)=f(n-1)+f(n-2),此时就转化为斐波那契数列,通过a,b = b,a+b即可进行迭代。

参考资料:王争《数据结构与算法之美》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值