返回

解开递归迷雾:通过二叉树力扣题掌握递归奥义

前端

白话递归 2:深入浅出二叉树递归解题

在浩瀚的算法海洋中,递归始终是一颗闪亮的明星。它的独特魅力就在于:将一个复杂的问题分解成更小的子问题,并在解决子问题的过程中不断缩小问题的规模,最终实现问题的解决。对于二叉树这类层级结构的数据结构,递归更是大显身手,帮助我们轻松破解一道道难题。

本文将结合力扣题库中的二叉树相关题目,循序渐进地剖析递归算法的精髓,助力大家轻松掌握递归解题技巧。

走进递归的殿堂

递归的本质是分而治之:将一个复杂问题分解成更小的子问题,然后重复使用相同的解决方法解决子问题,直到问题被彻底解决。对于二叉树这类树形结构,递归的应用更是如鱼得水。

1. 前序遍历:根左右

前序遍历的顺序是:先访问根节点,然后递归访问左子树,最后递归访问右子树。

def preorder(root):
    if root is None:
        return
    # 访问根节点
    print(root.val)
    # 递归访问左子树
    preorder(root.left)
    # 递归访问右子树
    preorder(root.right)

2. 中序遍历:左根右

中序遍历的顺序是:先递归访问左子树,然后访问根节点,最后递归访问右子树。

def inorder(root):
    if root is None:
        return
    # 递归访问左子树
    inorder(root.left)
    # 访问根节点
    print(root.val)
    # 递归访问右子树
    inorder(root.right)

3. 后序遍历:左右根

后序遍历的顺序是:先递归访问左子树,然后递归访问右子树,最后访问根节点。

def postorder(root):
    if root is None:
        return
    # 递归访问左子树
    postorder(root.left)
    # 递归访问右子树
    postorder(root.right)
    # 访问根节点
    print(root.val)

4. 递归总结

通过以上几个例子的分析,我们可以总结出二叉树递归解题的一般步骤:

  1. 递归基线: 检查树是否为空,如果为空则返回。
  2. 分解子问题: 根据遍历顺序,将树分解成更小的子树。
  3. 递归调用: 对子树递归调用相同的函数。
  4. 组合结果: 将子树的递归结果组合成最终结果。

力扣实战演练

1. 二叉树的最大深度(104)

力扣 104 题考察了二叉树的最大深度,即从根节点到最深叶节点的最长路径的长度。我们可以用递归来解决:

def maxDepth(root):
    if root is None:
        return 0
    # 计算左子树的最大深度
    left_depth = maxDepth(root.left)
    # 计算右子树的最大深度
    right_depth = maxDepth(root.right)
    # 返回左右子树最大深度中较大的那个加 1(根节点)
    return max(left_depth, right_depth) + 1

2. 二叉树的路径和(112)

力扣 112 题要求找到所有从根节点到叶节点的路径,且这些路径上的所有数字之和等于给定的目标值。我们也可以用递归来解决:

def hasPathSum(root, targetSum):
    if root is None:
        return False
    if root.left is None and root.right is None:
        return root.val == targetSum
    # 计算左子树的路径和
    left_sum = hasPathSum(root.left, targetSum - root.val)
    # 计算右子树的路径和
    right_sum = hasPathSum(root.right, targetSum - root.val)
    # 返回左右子树路径和中至少一个为 True
    return left_sum or right_sum

结语

通过对二叉树力扣题目的分析,我们对递归算法有了更深入的理解。递归的思想在于分而治之,通过不断分解子问题,最终将复杂问题化解为简单的可解形式。掌握了递归算法,我们就能轻松应对更多数据结构和算法难题,在编程进阶的道路上不断前行。