题目
给定二叉树的根节点 root ,返回所有左叶子之和。

解析
我的思路
递:
从根节点开始,所有左叶子之和=左子树的左叶子之和+右子树的左叶子之和
归:
-
当节点为空时,返回0;
-
当节点不为空时:
已知当左右子树为空时,该节点是叶子节点。
问题在于如何判断是否为左叶子呢?
在遍历某个节点的子树时,需要添加一个标识:
- 如果是左子树,标识为true;
- 如果是右子树,标识为false。
当标识为true且左右子树为空时,返回该节点的值。
灵神思路
题意:如果一个节点的左儿子是叶子,那么把左儿子的节点值加到答案中。
在遍历二叉树的过程中,如果当前节点的左儿子是叶子,即左儿子的左右儿子均为空,那么把左儿子的节点值加到答案中。
代码直接把 sumOfLeftLeaves 当作递归函数使用。
作者:灵茶山艾府
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
答案
我的答案:
javascript
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
function dfs(root, isleft) {
if(root === null) return 0;
if(isleft && root.left === null && root.right === null) return root.val;
return dfs(root.left, true) + dfs(root.right, false);
}
var sumOfLeftLeaves = function(root) {
// 递:每棵树的左叶子之和等于它的左右子树中的左叶子之和
// 归:节点为空时返回0,位于左子树且该节点的左、右子树均为空时(为叶子节点)返回该节点的值
return dfs(root.left, true) + dfs(root.right, false);
};
灵神答案:
javascript
var sumOfLeftLeaves = function(root) {
if (root === null) { // 空节点
return 0;
}
// 递归左右子树,收集左右子树中的「节点的左儿子是叶子」的叶子节点值之和
let sum = sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right);
const left = root.left; // 当前节点的左儿子
if (left && left.left === null && left.right === null) { // 当前节点的左儿子是叶子
sum += left.val; // 累加节点值
}
return sum;
};
// 作者:灵茶山艾府
// 链接:https://leetcode.cn/problems/sum-of-left-leaves/solutions/3751068/jian-dan-ti-jian-dan-zuo-pythonjavaccgoj-w8st/
// 来源:力扣(LeetCode)
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
**我的疑惑:**为什么在递归调用之后还要加一个判断来累加 root.left.val?
因为 在递归中,当前节点并不知道自己的左子节点是不是左叶子,除非站在父节点的视角判断。
递归逻辑分解
-
sumOfLeftLeaves(root.left)进入左子树,继续寻找左叶子(在左子树的视角里,它也会判断自己的左子节点是不是左叶子)。
-
sumOfLeftLeaves(root.right)进入右子树,继续寻找左叶子。
-
但是,
root的左子节点root.left如果是叶子,它在它自己的递归调用中不会被计入,因为:-
当递归进入
root.left时,它看到自己左右都为 null,但它不知道自己是父亲的左孩子还是右孩子。 -
在
root.left的递归中,root.left.left和root.left.right都是 null,所以不会进入 if 条件,只会返回 0。 -
所以
root.left如果是左叶子,必须由它的父节点 (root) 来识别并累加。
-
关键理解
-
递归调用
sumOfLeftLeaves(root.left)返回的是以root.left为根的树中所有的左叶子之和,并不包括root.left本身(如果它是叶子)。 -
判断一个节点是不是左叶子,必须由它的父节点来完成,因为需要知道它是左孩子还是右孩子,以及它是不是叶子。
-
所以代码结构是:
-
递归左右子树,收集它们之下的左叶子之和。
-
检查当前节点的直接左孩子是不是左叶子,如果是,加上它的值。
-
复杂度分析
时间复杂度:O(n),其中 n 是二叉树的节点个数。
空间复杂度:O(n)。最坏情况下,二叉树退化成一条链,递归需要 O(n) 的栈空间。