LeetCode 404简单二叉树 · DFS
左叶子之和 图解题解
这道题到底在问什么
给一棵二叉树的根节点,计算所有左叶子之和。左叶子 = 既是某个节点的左孩子,本身又是叶子(没有孩子)。
- 树
- [3,9,20,null,null,15,7]
- 输出
- 24
- 说明
- 左叶子是 9 和 15,9 + 15 = 24
先想最直接的笨办法
笨办法也是好办法:挨个访问每个节点。判断的主语不是「我自己」,而是「我的左孩子」——只要我的左孩子是叶子,那它就是一个左叶子,加上它的值。(动画第 7 步)
最优解:一步一步想明白
- 3千万别只看「是不是叶子」。7 是叶子,但它是 20 的右孩子,不算;20 是 3 的右孩子,而且它下面挂着 15、7、不是叶子,更不算。两条都满足才数。
- 4根=3, 左叶子=9 / 15绿色的 9 和 15 就是要找的左叶子。9 是根 3 的左孩子且没孩子;15 是 20 的左孩子且没孩子。其它节点都不数。
- 57 是叶子,但是「右」孩子同样挂在 20 下面:15 是左孩子所以数,7 是右孩子所以不数。这就是「左」字的分量,位置不同,结果天差地别。
- 620 是右孩子,而且不是叶子再看 20:它是根 3 的右孩子、本身又不是叶子(下面挂着 15 和 7),两条全不沾,自然也不数。「左孩子」和「叶子」两条得同时满足。
- 7笨办法也是好办法:挨个访问每个节点。判断的主语不是「我自己」,而是「我的左孩子」——只要我的左孩子是叶子,那它就是一个左叶子,加上它的值。
- 8sum = 0,看 3 的左孩子从根 3 出发,答案 sum = 0。规矩是:站在 3 这里,先看一眼它的左孩子 9 是不是叶子。
- 9目光移到 9把目光移到 3 的左孩子 9。接下来要查两件事:9 有没有左孩子、有没有右孩子——两个都空才是叶子。
- 109 左右都空 → 是左叶子!3 的左孩子是 9。看 9:它左右都没孩子 → 9 是叶子,而且它是 3 的左孩子 → 它是一个左叶子,该累加了。
- 11sum = 0 + 9 = 9把 9 标成绿色(已收),sum 从 0 变成 9。第一个左叶子到手。接着 DFS 继续探 3 的左右孩子(标准遍历)。
- 12递归进入 9虽然 9 已经被数过了,DFS 仍会递归走进 9(代码是统一遍历)。进到 9 后看它的左孩子——是空,没有可数的左叶子,这一支到头了。
- 139 左右都空,退回 39 没有任何孩子,递归直接返回,退回根 3。9 标灰(已探完)。3 的左边走完了,接下来按 DFS 规矩去探 3 的右孩子 20。
- 14递归进入 20,看 20 的左孩子进入 20。同样的动作:站在 20 这里,先看它的左孩子 15 是不是叶子。注意 sum 此刻仍是 9,还没加新东西。
- 15目光移到 15把目光移到 20 的左孩子 15。和刚才查 9 一样,要确认 15 的左右孩子是不是都空。
- 1615 左右都空 → 是左叶子!20 的左孩子是 15。看 15:左右都空 → 是叶子,又是 20 的左孩子 → 第二个左叶子找到了,该加。
- 17sum = 9 + 15 = 24把 15 标绿,sum 从 9 变成 24。两个左叶子都数到了。接下来 DFS 继续把 20 的左右孩子也走一遍(确认没漏)。
- 187 是叶子,但是右孩子 → 不加顺手看 20 的右孩子 7:它确实是叶子,但它是右孩子,不满足「左」这一条,所以不加。sum 保持 24 不动。
- 1915 是叶子,无可探DFS 还会递归走进 15(统一遍历)。15 没孩子,看它的左孩子是空,无左叶子可加,直接返回。sum 仍是 24。
- 207 是叶子,无可探再递归走进 7。7 也没孩子,它的左孩子是空,无左叶子可加,返回。注意:7 自己虽是叶子,但「数不数它」是在它父亲 20 那一步判的,这里不重复判。
- 21退回节点 207 探完返回,退回 20。15、7 都标灰了。20 的左右孩子都走完,它这一支也该收口,继续往上退回根 3。
- 2220 的子树全走完20 这棵子树(15、7)全探完,标灰退回根 3。此时 3 的左孩子 9、右孩子 20 都走过了,整棵树遍历结束。
- 23答案 sum = 24遍历完毕,两个左叶子 9、15 累加得 24。整个过程就是:走到每个节点,顺手判一下「我的左孩子是不是叶子」,是就加上它。
- 24为什么不站在叶子上判?因为叶子不知道自己是父亲的左孩子还是右孩子(它没有指向父亲的指针)。让父亲来判左孩子,信息现成,一句 if 搞定。
- 28错误: sum = 9 + 15 + 7 = 31如果只判「是不是叶子」、不管左右,就会把 7 也加进去得到 31。7 是右孩子,不是左叶子。漏掉「左」这个条件,答案就错了。
⚠️ 容易写错的地方
✗ 错:把所有叶子的值都加起来
✓ 对:只加「左孩子且是叶子」的节点
右叶子(如本题的 7)不能算,会把答案算大
✗ 错:站在叶子上判断自己是不是左叶子
✓ 对:站在父节点上判断「我的左孩子是不是叶子」
叶子拿不到父亲指针,不知道自己是左还是右孩子
✗ 错:左孩子是叶子后还继续递归进它
✓ 对:命中左叶子就加值、不再递归进它
它已被当左叶子数过,再递归虽不重复加但逻辑该收口
完整代码(Python / C++ / Java)
Python
class Solution:
def sumOfLeftLeaves(self, root):
if not root:
return 0
s = 0
left = root.left
if left and not left.left and not left.right:
s += left.val # 左孩子是叶子 → 左叶子,累加
else:
s += self.sumOfLeftLeaves(left) # 否则继续往左探
s += self.sumOfLeftLeaves(root.right) # 右子树照常探
return sC++
class Solution {
public:
int sumOfLeftLeaves(TreeNode* root) {
if (!root) return 0;
int s = 0;
TreeNode* left = root->left;
if (left && !left->left && !left->right) // 左孩子是叶子
s += left->val; // 累加左叶子
else
s += sumOfLeftLeaves(left); // 否则继续探左
s += sumOfLeftLeaves(root->right); // 探右
return s;
}
};Java
class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) return 0;
int s = 0;
TreeNode left = root.left;
if (left != null && left.left == null && left.right == null) // 左孩子是叶子
s += left.val; // 累加左叶子
else
s += sumOfLeftLeaves(left); // 否则继续探左
s += sumOfLeftLeaves(root.right); // 探右
return s;
}
}复杂度
时间复杂度
O(n)
每个节点最多被访问一次,n 个节点 → O(n)
空间复杂度
O(h)
递归栈最深 = 树高 h;最坏(斜树)O(n),平衡时 O(log n)
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 左叶子之和 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
递归的判定主语是谁?+
父节点。在父节点上判断「root.left 是否存在且是叶子」,是则累加 root.left.val。
怎么用迭代(栈/队列)实现?+
层序或前序遍历每个节点,出栈时检查它的左孩子是不是叶子,是就累加,然后把左右孩子入栈继续。
如果改成「右叶子之和」怎么改?+
把判定换成 root.right 是否为叶子即可,其余结构完全一样。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 左叶子之和 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。