404. 左叶子之和(Sum of Left Leaves)
频次 ★★ · 难度 🟢 · 高频:全厂
题目
计算二叉树所有左叶子节点值的和。左叶子:是父节点的左子节点,且自身是叶子节点(左右子节点都为空)。
示例:
输入: 3
/ \
9 20
/ \
15 7
输出: 24(左叶子 9 + 15 = 24)
思路
递归判断”当前节点的左子节点是否是叶子”:遍历每个节点,检查其左子节点——如果左子节点存在且左右都为空,说明它是左叶子,累加其值。然后递归处理左右子树。
关键:不能从叶子节点自身判断(叶子节点不知道自己是左还是右),必须从父节点判断。
代码
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) return 0;
int sum = 0;
// 判断当前节点的左子节点是否是左叶子
if (root.left != null
&& root.left.left == null
&& root.left.right == null) {
sum += root.left.val;
}
// 递归处理左右子树
return sum + sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
}复杂度
- 时间:O(n) —— 每个节点访问一次
- 空间:O(height) —— 递归栈深度
边界条件
- 空树:返回 0
- 单节点:0(根节点不算左叶子)
- 根节点的左子节点是叶子:累加该值
- 所有节点都在右子树:0(没有左叶子)
变式
- 右叶子之和:判断条件改为
root.right且左右为空 - 所有叶子之和:不需要判断左右,直接累加
- 迭代版:用栈/队列遍历,同样在父节点判断左子节点
易错点
- 不能从叶子节点判断——叶子节点
node.left == null && node.right == null成立,但无法知道自己是左还是右。必须在父节点层面判断root.left是否是叶子 - 递归调用时,
sumOfLeftLeaves(root.left)会继续检查左子节点中的左叶子——不需要额外判断 - 不要写成
sumOfLeftLeaves(root.left.left)之类的——递归已经处理了
面试追问
- 怎么判断一个节点是左叶子? 两个条件:1) 它是父节点的左子节点;2) 它自己没有子节点。前者需要从父节点视角判断,后者可以直接判断
- 迭代怎么写? 用栈/队列,每次弹出节点后检查其左子节点是否是叶子,是则累加。注意迭代时也要把左子节点和右子节点入栈/队
关联题
- 同套路:112. 路径总和 —— 递归时在叶子节点做判断的模式
- 进阶:513. 找树左下角的值 —— 同样关注”左”侧,但找的是最底层最左的节点
- 知识点:递归时从父节点视角判断子节点属性的模式见二叉树