二叉树入门必刷 4 题:掌握递归三板斧,搞定 80% 二叉树题目

二叉树入门必刷 4 题:掌握递归三板斧,搞定 80% 二叉树题目

前言

很多人刚开始刷二叉树的时候都有一个共同感受:

看懂了题解,但下次遇到类似题还是不会写。

原因很简单。

二叉树题目看起来很多,但本质上都在考察几种固定模式:

  • 遍历树
  • 计算树的属性
  • 修改树的结构
  • 判断树的关系

今天刷完 LeetCode 的 4 道经典二叉树题后,我发现它们刚好覆盖了二叉树最核心的知识体系:

    1. 二叉树中序遍历
    1. 二叉树最大深度
    1. 翻转二叉树
    1. 对称二叉树

如果能够真正理解这四道题,后面绝大多数树题都会轻松很多。

本文就从题目、技巧、模板和易错点四个角度进行系统总结。


为什么二叉树题目都喜欢用递归?

先看一棵简单二叉树:

        1
       / \
      2   3
     / \
    4   5

会发现一个特点:

节点下面还是树。

左子树是一棵树。

右子树也是一棵树。

因此二叉树天然具有:

大问题 = 左子树问题 + 右子树问题

这种结构特别适合递归。

所以刷树时一定记住:

能用递归解决的树题,优先考虑递归。


LeetCode 94:二叉树中序遍历

题目要求

按照:

左子树 → 根节点 → 右子树

顺序遍历整棵树。


递归思路

中序遍历其实就是严格执行:

遍历左子树

访问当前节点

遍历右子树

代码框架:

def dfs(node):

    if not node:
        return

    dfs(node.left)

    res.append(node.val)

    dfs(node.right)

本题考察什么?

实际上考察的是:

树的遍历思想

后续所有遍历题:

  • 前序遍历
  • 后序遍历
  • 路径问题
  • 节点统计

都来源于这一套框架。


易错点

忘记终止条件

if not node:
    return

这是所有树递归的生命线。


遍历顺序写错

很多同学会把:

左 → 根 → 右

写成:

根 → 左 → 右

结果变成前序遍历。


LeetCode 104:二叉树最大深度

题目要求

求根节点到最远叶子节点的路径长度。


核心公式

这题建议直接背下来:

空节点深度 = 0

当前节点深度 =
max(左子树深度, 右子树深度) + 1

递归代码框架

def maxDepth(root):

    if not root:
        return 0

    left = maxDepth(root.left)

    right = maxDepth(root.right)

    return max(left, right) + 1

本题考察什么?

考察:

分治思想

把整棵树拆成:

求左子树深度

求右子树深度

最后再合并答案。


易错点

忘记加 1

错误写法:

return max(left, right)

正确写法:

return max(left, right) + 1

因为当前节点本身也算一层。


LeetCode 226:翻转二叉树

题目要求

把整棵树左右镜像翻转。

例如:

原树:

    1
   / \
  2   3

翻转后:

    1
   / \
  3   2

核心思想

很多人第一反应:

交换 val

这是错的。


真正翻转的是:

left 指针

right 指针

而不是节点值。


递归框架

def invertTree(root):

    if not root:
        return None

    root.left, root.right = (
        invertTree(root.right),
        invertTree(root.left)
    )

    return root

本题考察什么?

考察:

修改树结构

之前两题是读取树。

这题开始修改树。


易错点

交换节点值

错误:

root.left.val
root.right.val

交换数值。


正确:

root.left
root.right

交换指针。


LeetCode 101:对称二叉树

题目要求

判断一棵树是否关于中心轴对称。


例如:

        1
      /   \
     2     2
    / \   / \
   3  4  4  3

属于对称树。


核心思想

不要判断:

左子树是否对称

右子树是否对称

这是错误思路。


应该判断:

左子树和右子树是否互为镜像

镜像判断规则

给定两个节点:

p

q

需要满足:

情况1

p == None

q == None

返回 True


情况2

一个为空一个不为空

返回 False


情况3

值相等

同时满足:

p.left  ↔ q.right

p.right ↔ q.left

递归框架

def check(p, q):

    if not p and not q:
        return True

    if not p or not q:
        return False

    return (
        p.val == q.val
        and check(p.left, q.right)
        and check(p.right, q.left)
    )

本题考察什么?

这是第一道典型:

双节点递归

前面题目递归参数:

dfs(node)

只有一个节点。


这里变成:

check(node1, node2)

同时处理两个节点。

这是后面:

  • 相同的树
  • 子树判断
  • 镜像树

等题目的基础。


二叉树递归三板斧

今天四道题全部遵循同一个套路。

以后看到树题都先套这个模板。


第一步:递归终止

if not node:
    return ?

第二步:递归处理左右子树

left = dfs(node.left)

right = dfs(node.right)

第三步:处理当前节点

根据题目需求:

  • 收集节点
  • 计算深度
  • 交换指针
  • 判断镜像

记住一句话:

先解决左右子树,再处理当前节点。

这是树递归的核心思想。


什么时候需要辅助函数?

很多同学刷树时经常纠结:

要不要写内部函数?

其实规律很简单。


不需要辅助函数

只有一个节点参数。

结果通过 return 返回。

例如:

  • 最大深度
  • 翻转二叉树

需要辅助函数

收集结果

例如:

res.append(...)

需要共享列表。


多参数递归

例如:

check(p, q)

需要同时处理多个节点。


传递额外信息

例如:

  • 当前路径
  • 当前层数
  • 路径和

都需要辅助函数。


高频易错点总结

1. 忘记空节点判断

所有树递归第一件事:

if not root:

2. 搞混结构和数值

翻转树:

交换指针。

不是交换 val。


3. 忘记递归返回值

例如最大深度:

return max(left,right)+1

必须返回。


4. 镜像比较顺序写错

正确:

left.left ↔ right.right

left.right ↔ right.left

5. 把节点数量当成树深度

深度:

层数

不是:

节点总数

总结

今天这四道题虽然看起来不同,但本质都在训练同一个能力:

递归处理二叉树。

如果把二叉树比作一个知识体系:

  • 94 中序遍历 → 学会遍历
  • 104 最大深度 → 学会计算属性
  • 226 翻转二叉树 → 学会修改结构
  • 101 对称二叉树 → 学会判断关系

真正掌握这四道题之后,后续大部分树题都能快速找到解题方向。

最后留一个思考题:

为什么二叉树最大深度不需要辅助函数,而中序遍历却必须借助辅助函数或额外列表?

欢迎在评论区交流你的理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值