LeetCode 分类刷题:404. 左叶子之和

题目

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

解析

我的思路

递:

从根节点开始,所有左叶子之和=左子树的左叶子之和+右子树的左叶子之和

归:

  1. 当节点为空时,返回0;

  2. 当节点不为空时:

已知当左右子树为空时,该节点是叶子节点。

问题在于如何判断是否为左叶子呢?

在遍历某个节点的子树时,需要添加一个标识:

  • 如果是左子树,标识为true;
  • 如果是右子树,标识为false。

当标识为true且左右子树为空时,返回该节点的值。

灵神思路

题意:如果一个节点的左儿子是叶子,那么把左儿子的节点值加到答案中。

在遍历二叉树的过程中,如果当前节点的左儿子是叶子,即左儿子的左右儿子均为空,那么把左儿子的节点值加到答案中。

代码直接把 sumOfLeftLeaves 当作递归函数使用。

作者:灵茶山艾府

链接:https://leetcode.cn/problems/sum-of-left-leaves/solutions/3751068/jian-dan-ti-jian-dan-zuo-pythonjavaccgoj-w8st/

来源:力扣(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?

因为 在递归中,当前节点并不知道自己的左子节点是不是左叶子,除非站在父节点的视角判断。

递归逻辑分解

  1. sumOfLeftLeaves(root.left)

    进入左子树,继续寻找左叶子(在左子树的视角里,它也会判断自己的左子节点是不是左叶子)。

  2. sumOfLeftLeaves(root.right)

    进入右子树,继续寻找左叶子。

  3. 但是,root 的左子节点 root.left 如果是叶子,它在它自己的递归调用中不会被计入,因为:

    • 当递归进入 root.left 时,它看到自己左右都为 null,但它不知道自己是父亲的左孩子还是右孩子。

    • root.left 的递归中,root.left.leftroot.left.right 都是 null,所以不会进入 if 条件,只会返回 0。

    • 所以 root.left 如果是左叶子,必须由它的父节点 (root) 来识别并累加。

关键理解

  • 递归调用 sumOfLeftLeaves(root.left) 返回的是以 root.left 为根的树中所有的左叶子之和,并不包括 root.left 本身(如果它是叶子)。

  • 判断一个节点是不是左叶子,必须由它的父节点来完成,因为需要知道它是左孩子还是右孩子,以及它是不是叶子。

  • 所以代码结构是:

    1. 递归左右子树,收集它们之下的左叶子之和。

    2. 检查当前节点的直接左孩子是不是左叶子,如果是,加上它的值。

复杂度分析

时间复杂度:O(n),其中 n 是二叉树的节点个数。

空间复杂度:O(n)。最坏情况下,二叉树退化成一条链,递归需要 O(n) 的栈空间。

相关推荐
竹林8181 小时前
Web3表单签名验证:我用 wagmi 和 ethers 给 DApp 加了一个“免密登录”,踩坑记录全在这了
javascript
用户6990304848752 小时前
try catch使用场景 处理同步代码错误兼容用的
javascript·uni-app
雪碧聊技术2 小时前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript
通信小呆呆2 小时前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
VidDown2 小时前
VidDown 工具站:免费、本地优先的开发者工具箱
javascript·编辑器·音视频·视频编解码·视频
benben0442 小时前
强化学习之DQN算法族(基于gymnasium开发)
算法
何以解忧,唯有..3 小时前
Go语言循环语句详解:for、range与循环控制
开发语言·算法·golang
触底反弹3 小时前
🚀 手把手用 HTML5 Canvas 从零打造飞机大战游戏,代码全开源!
前端·javascript·canvas
DJ斯特拉3 小时前
axios快速使用
开发语言·前端·javascript