【Hot100】8.二叉树
这一类的核心思想是:递归(DFS)与层次遍历(BFS)。
- 递归 (DFS):二叉树的天然定义就是递归的(根 + 左子树 + 右子树)。绝大多数题目(深度、对称、翻转、LCA)都可以用简洁的递归解决。
- 前序:处理根 -> 左 -> 右(适合复制、翻转)。
- 中序:左 -> 处理根 -> 右(适合 BST 验证、排序)。
- 后序:左 -> 右 -> 处理根(适合计算深度、LCA,因为需要先知道子树信息)。
- 层次遍历 (BFS):利用队列 (Queue),按层处理节点。适用于求层序遍历、最小深度、宽度等。
- BST 特性:对于二叉搜索树,利用
左 < 根 < 右的特性进行剪枝或验证。
📝 本类题型总结
| 题目 | 核心技巧 | 关键差异点 (vs 最大深度) |
|---|---|---|
| 104. 最大深度 | 基础 DFS | 基准:1 + max(left, right)。 |
| 101. 对称二叉树 | 双节点 DFS | 函数传 p, q。交叉比较 (p.left vs q.right)。 |
| 226. 翻转二叉树 | 交换 + DFS | 先交换当前左右孩子,再递归。 |
| 102. 层序遍历 | BFS + 队列 | 用队列。利用 size 分层处理。 |
| 98. 验证 BST | 带边界 DFS | 递归需传 min, max。判断 min < val < max。 |
| 236. 最近公共祖先 | 后序 DFS | 左右返回值都不空时,当前即为答案;否则返回非空的那个。 |
🏆 母题:LeetCode 104. 二叉树的最大深度 (Maximum Depth of Binary Tree)
题目内容:给定一个二叉树 root ,返回其最大深度。
核心逻辑:
- 终止条件:节点为空,深度为 0。
- 递归关系:当前深度 =
1 + max(左子树深度, 右子树深度)。 - 遍历顺序:后序遍历(先算出左右子树深度,再计算当前)。
class Solution {
public int maxDepth(TreeNode root) {
// ⚠️ [终止条件] 空节点深度为 0
if (root == null) return 0;
// ⚠️ [核心逻辑] 递归计算左右子树深度,取最大值 + 1
int leftDepth = maxDepth(root.left);
int rightDepth = maxDepth(root.right);
return 1 + Math.max(leftDepth, rightDepth);
}
}
🔄 变体 1:LeetCode 101. 对称二叉树 (Symmetric Tree)
题目内容:给你一个二叉树的根节点 root , 检查它是否轴对称。
相比母题的变化:
- 递归函数签名:需要传入两个节点
check(p, q),分别代表左子树和右子树的对应节点。 - 判断逻辑:
- 若
p和q都为空:对称。 - 若只有一个为空 或
p.val != q.val:不对称。 - 核心递归:
p的左孩子 必须等于q的右孩子,且p的右孩子 必须等于q的左孩子(交叉比较)。
- 若
class Solution {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return check(root.left, root.right);
}
// ⚠️ [变化点 1] 辅助函数接收两个节点
private boolean check(TreeNode p, TreeNode q) {
// 都为空,对称
if (p == null && q == null) return true;
// 一个为空或值不等,不对称
if (p == null || q == null || p.val != q.val) return false;
// ⚠️ [变化点 2] 交叉递归比较
// 左子的左 vs 右子的右,且 左子的右 vs 右子的左
return check(p.left, q.right) && check(p.right, q.left);
}
}
🔄 变体 2:LeetCode 226. 翻转二叉树 (Invert Binary Tree)
题目内容:给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
相比母题的变化:
- 操作时机:前序遍历(先交换当前节点的左右孩子,再递归子树)或 后序遍历 均可。通常前序更直观。
- 核心动作:
swap(root.left, root.right)。
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) return null;
// ⚠️ [变化点 1] 交换当前节点的左右子节点
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
// ⚠️ [变化点 2] 递归翻转左右子树
invertTree(root.left);
invertTree(root.right);
return root;
}
}
🔄 变体 3:LeetCode 102. 二叉树的层序遍历 (Binary Tree Level Order Traversal)
题目内容:给你二叉树的根节点 root ,返回其节点值的 层序遍历 (即逐层地,从左到右访问所有节点)。
相比母题的变化:
- 数据结构:使用 队列 (Queue) 实现 BFS,而非递归栈。
- 分层逻辑:
- 每次循环开始前,记录当前队列大小
size = queue.size(),这就是当前层的节点数。 - 内部循环
size次,弹出节点并将下一层节点入队。 - 将每一层的结果存入一个列表,最后加入大列表。
- 每次循环开始前,记录当前队列大小
import java.util.*;
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) return result;
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
// ⚠️ [变化点 1] 获取当前层的节点数量
int size = queue.size();
List<Integer> level = new ArrayList<>();
// ⚠️ [变化点 2] 只处理当前层的 size 个节点
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
level.add(node.val);
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
}
result.add(level);
}
return result;
}
}
🔄 变体 4:LeetCode 98. 验证二叉搜索树 (Validate Binary Search Tree)
题目内容:给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 BST 定义:
- 节点的左子树只包含 小于 当前节点的数。
- 节点的右子树只包含 大于 当前节点的数。
- 所有左子树和右子树自身必须也是二叉搜索树。
相比母题的变化: - 陷阱:不能只比较
root.val和直接左右孩子(如root.left.val < root.val),必须保证左子树所有节点都小于根,右子树所有节点都大于根。 - 递归参数:需要传递 上下界
(min, max)。- 初始调用:
isValid(root, Long.MIN_VALUE, Long.MAX_VALUE)。 - 左子树递归:上界变为
root.val->isValid(left, min, root.val)。 - 右子树递归:下界变为
root.val->isValid(right, root.val, max)。
- 初始调用:
class Solution {
public boolean isValidBST(TreeNode root) {
return validate(root, Long.MIN_VALUE, Long.MAX_VALUE);
}
// ⚠️ [变化点 1] 增加 min 和 max 边界参数
private boolean validate(TreeNode node, long min, long max) {
if (node == null) return true;
// ⚠️ [变化点 2] 检查当前节点是否在合法范围内 (开区间)
if (node.val <= min || node.val >= max) return false;
// ⚠️ [变化点 3] 递归时更新边界
// 左子树:最大值不能超过 node.val
// 右子树:最小值不能小于 node.val
return validate(node.left, min, node.val) &&
validate(node.right, node.val, max);
}
}
🔄 变体 5:LeetCode 236. 二叉树的最近公共祖先 (Lowest Common Ancestor)
题目内容:给定一个二叉树, 找到该树中两个指定节点 p 和 q 的最近公共祖先。
相比母题的变化:
- 遍历顺序:后序遍历(左右根)。因为我们需要知道左右子树是否包含了
p或q,才能决定当前节点是不是 LCA。 - 逻辑判断:
- 若当前节点是
p或q,直接返回当前节点。 - 递归左右子树,得到
left和right。 - 情况 A:
left和right都不为空 -> 说明p和q分别在两侧,当前节点即为 LCA。 - 情况 B:
left不为空,right为空 -> 说明p, q都在左子树,返回left。 - 情况 C:
right不为空,left为空 -> 说明p, q都在右子树,返回right。
- 若当前节点是
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
// ⚠️ [终止条件] 遇到空节点,或遇到 p/q,直接返回
if (root == null || root == p || root == q) {
return root;
}
// ⚠️ [变化点 1] 后序遍历:先查左右
TreeNode left = lowestCommonAncestor(root.left, p, q);
TreeNode right = lowestCommonAncestor(root.right, p, q);
// ⚠️ [变化点 2] 核心判断逻辑
if (left != null && right != null) {
// p 和 q 分别在左右两侧,当前 root 就是 LCA
return root;
}
// 哪边非空就返回哪边(如果都空则返回 null)
return (left != null) ? left : right;
}
}

浙公网安备 33010602011771号