LeetCode 404.左叶子之和的迭代求解:栈结构与父节点定位的深度解析

news2025/5/23 20:16:52

一、题目解析:左叶子的定义与问题本质

题目描述

LeetCode 404. 左叶子之和要求计算二叉树中所有左叶子节点的值之和。左叶子的定义是:如果一个节点是其父节点的左子节点,并且它本身没有左右子节点,则称为左叶子

关键要点

  1. 左叶子的双重条件
    • 必须是父节点的左子节点;
    • 自身没有子节点(左右子节点均为空)。
  2. 问题本质:需要在遍历二叉树的过程中,判断每个节点是否为左叶子,并累加其值。

示例说明

对于二叉树:

    3
   / \
  9  20
    /  \
   15   7

左叶子为9和15,和为24。

二、迭代解法核心:栈结构与父节点定位逻辑

代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        Stack<TreeNode> cur = new Stack<>();
        if (root == null) {
            return 0;
        }
        int res = 0;
        TreeNode temp = root;
        cur.push(root);
        while (!cur.empty()) {
            temp = cur.pop();
            // 检查左子节点是否为左叶子
            if (temp.left != null && temp.left.left == null && temp.left.right == null) {
                res += temp.left.val;
            }
            // 先压右子节点,再压左子节点(保证左子树先处理)
            if (temp.right != null) {
                cur.push(temp.right);
            }
            if (temp.left != null) {
                cur.push(temp.left);
            }
        }
        return res;
    }
}

核心设计解析:为什么选择栈结构?

1. 栈的特性与深度优先遍历
  • 栈的后进先出(LIFO)特性天然适合深度优先遍历(DFS):
    • 先压入右子节点,再压入左子节点,确保左子树先于右子树处理;
    • 模拟递归调用栈的行为,避免递归可能导致的栈溢出。
2. 栈中存储父节点的必要性
  • 左叶子的判断依赖于父节点:
    • 必须通过父节点才能确定当前节点是否为左子节点;
    • 栈中存储的是父节点,而非当前叶子节点,因此可以直接通过temp.left判断左子节点是否为叶子。

三、父节点定位左叶子的逻辑深度解析

1. 左叶子的判断条件

if (temp.left != null && temp.left.left == null && temp.left.right == null) {
    res += temp.left.val;
}
  • 条件拆解
    1. temp.left != null:父节点存在左子节点;
    2. temp.left.left == null:左子节点没有左子节点;
    3. temp.left.right == null:左子节点没有右子节点。
  • 逻辑本质:通过父节点temp判断其左子节点是否为叶子节点,满足条件则累加值。

2. 栈操作顺序与遍历顺序

if (temp.right != null) {
    cur.push(temp.right);
}
if (temp.left != null) {
    cur.push(temp.left);
}
  • 入栈顺序:先右子节点,后左子节点;
  • 出栈顺序:先左子节点,后右子节点(LIFO);
  • 效果:实现深度优先遍历中的先左后右顺序,与递归的前序遍历一致。

3. 栈操作模拟:以示例二叉树为例

示例二叉树:
    3
   / \
  9  20
    /  \
   15   7
栈操作流程:
  1. 初始状态
    栈:[3],结果res=0

  2. 第一次循环

    • 弹出3,检查左子节点9
      93的左子节点,且9没有子节点,累加9res=9
    • 压入右子节点20,左子节点9(已处理,无需重复处理?不,此处压入的是父节点的子节点);
      栈:[20, 9]
  3. 第二次循环

    • 弹出9,检查左子节点(9的左子节点为空),无操作;
    • 压入9的右子节点(空),左子节点(空);
      栈:[20]
  4. 第三次循环

    • 弹出20,检查左子节点15
      1520的左子节点,且15没有子节点,累加15res=24
    • 压入20的右子节点7,左子节点15
      栈:[7, 15]
  5. 第四次循环

    • 弹出15,检查左子节点(空),无操作;
    • 压入15的右子节点(空),左子节点(空);
      栈:[7]
  6. 第五次循环

    • 弹出7,检查左子节点(空),无操作;
    • 压入7的右子节点(空),左子节点(空);
      栈:空
  7. 最终结果res=24

四、栈结构的核心作用:模拟递归与状态维护

1. 迭代与递归的等价性

递归实现迭代栈实现
系统自动维护调用栈手动维护栈保存节点
代码简洁但可能栈溢出代码直观且栈深度可控
隐式保存父节点上下文显式通过父节点判断叶子

2. 时间与空间复杂度分析

  • 时间复杂度:O(n),每个节点仅访问一次;
  • 空间复杂度:O(h),h为树的高度,最坏情况下(链表树)为O(n)。

3. 大厂面试中的考点分析

  • 栈的选择:考察对数据结构特性的理解(LIFO适合DFS);
  • 父节点定位:考察对左叶子定义的理解(必须通过父节点判断);
  • 迭代与递归转换:考察算法实现的灵活性。

五、左叶子判断的常见误区与优化

1. 常见误区

  • 误判非左子节点为左叶子
    仅判断节点是否为叶子,忽略“左子节点”的条件。例如:
    if (node.left == null && node.right == null) { // 错误,未判断是否为左子节点
        res += node.val;
    }
    

2. 优化方向:层序遍历(BFS)实现

public int sumOfLeftLeaves(TreeNode root) {
    if (root == null) return 0;
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    int res = 0;
    while (!queue.isEmpty()) {
        TreeNode node = queue.poll();
        if (node.left != null) {
            // 左子节点是叶子
            if (node.left.left == null && node.left.right == null) {
                res += node.left.val;
            } else {
                queue.offer(node.left);
            }
        }
        if (node.right != null) {
            queue.offer(node.right);
        }
    }
    return res;
}
  • 对比
    • 时间复杂度相同(O(n));
    • 空间复杂度可能更高(队列平均宽度可能大于栈深度);
    • 代码逻辑更直观,适合初学者理解。

3. 极端情况处理

  • 单节点树:根节点不是左叶子(无父节点),返回0;
  • 只有右子树:所有叶子均非左叶子,返回0;
  • 完全左斜树:所有左子节点若为叶子则累加,如树1->2->3->4,左叶子为2、3、4,和为9。

六、总结:迭代法求解左叶子之和的核心要点

1. 栈结构的双重作用

  • 作为遍历容器,实现深度优先搜索;
  • 保存父节点,为左叶子判断提供上下文。

2. 左叶子判断的关键

  • 必须同时满足“左子节点”和“叶子节点”两个条件;
  • 通过父节点的left指针访问左子节点,判断其是否为叶子。

3. 算法设计的核心思想

  • 状态维护:栈中保存的是父节点状态,而非叶子节点;
  • 遍历顺序:通过栈的入栈顺序控制遍历顺序,实现深度优先;
  • 条件过滤:在遍历过程中实时判断左叶子,避免额外存储。

这种迭代解法充分展示了栈结构在树遍历中的灵活性——通过维护父节点状态,精准定位左叶子节点。理解这种“父节点定位”的思想,对解决类似需要依赖上下文的树节点问题(如求祖父节点值、子树和等)具有重要的借鉴意义。在实际工程中,迭代法因避免递归栈溢出,更适合处理大规模树结构,是大厂面试中需要重点掌握的技能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2384125.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity-编辑器扩展

之前我们关于Unity的讨论都是针对于Unity底层的内容或者是代码层面的东西&#xff0c;这一次我们来专门研究Unity可视化的编辑器&#xff0c;在已有的基础上做一些扩展。 基本功能 首先我们来认识三个文件夹&#xff1a; Editor&#xff0c;Gizmos&#xff0c;Editor Defaul…

Lucide:一款精美的开源矢量图标库,前端图标新选择

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、前言&#xff1a;为何选择 Lucide&#xff1f;二、Lucide 是什么&#xff1f;1.…

Mac如何允许安装任何来源软件?

打开系统偏好设置-安全性与隐私&#xff0c;点击右下角的解锁按钮&#xff0c;选择允许从任何来源。 如果没有这一选项&#xff0c;请到打开终端&#xff0c;输入命令行&#xff1a;sudo spctl --master-disable, 输入命令后回车&#xff0c;输入电脑的开机密码后回车。 返回“…

2025最新版Visual Studio Code for Mac安装使用指南

2025最新版Visual Studio Code for Mac安装使用指南 Installation and Application Guide to The Latest Version of Visual Studio Code in 2025 By JacksonML 1. 什么是Visual Studio Code&#xff1f; Visual Studio Code&#xff0c;通常被称为 VS Code&#xff0c;是由…

【嵙大o】C++作业合集

​ 参考&#xff1a; C swap&#xff08;交换&#xff09;函数 指针/引用/C自带-CSDN博客 Problem IDTitleCPP指针CPP引用1107 Problem A编写函数&#xff1a;Swap (I) (Append Code)1158 Problem B整型数据的输出格式1163 Problem C时间&#xff1a;24小时制转12小时制1205…

C++23 范围迭代器作为非范围算法的输入 (P2408R5)

文章目录 一、引言二、C23及范围迭代器的背景知识2.1 C23概述2.2 范围迭代器的概念 三、P2408R5提案的内容3.1 提案背景3.2 提案内容 四、范围迭代器作为非范围算法输入的优势4.1 代码简洁性4.2 提高开发效率4.3 更好的兼容性 五、具体的代码示例5.1 使用范围迭代器进行并行计算…

2025.05.20【Treemap】树图数据可视化技巧

Multi-level treemap How to build a treemap with group and subgroups. Customization Customize treemap labels, borders, color palette and more 文章目录 Multi-level treemapCustomization Treemap 数据可视化技巧什么是 TreemapTreemap 的应用场景如何在 R 中绘制 T…

深入了解Springboot框架的启动流程

目录 1、介绍 2、执行流程 1、运行run方法 2、初始化SpringApplication对象 1、确定容器类型 3、加载所有的初始化器 4、加载Spring上下文监听器 5、设置程序运行的主类 3、进入run方法 1、开启计时器 2、Headless模式配置 3、获取并启用监听器 4、准备环境 1、设…

LLaMA-Factory微调LLM-Research/Llama-3.2-3B-Instruct模型

1、GPU环境 nvidia-smi 2、pyhton环境安装 git clone https://github.com/hiyouga/LLaMA-Factory.git conda create -n llama_factory python3.10 conda activate llama_factory cd LLaMA-Factory pip install -e .[torch,metrics] 3、微调模型下载&#xff08;LLM-Research/…

3.8.1 利用RDD实现词频统计

在本次实战中&#xff0c;我们通过Spark的RDD实现了词频统计功能。首先&#xff0c;准备了包含单词的文件并上传至HDFS。接着&#xff0c;采用交互式方式逐步完成词频统计&#xff0c;包括创建RDD、单词拆分、映射为二元组、按键归约以及排序等操作。此外&#xff0c;还通过创建…

Spring Ioc和Aop,Aop的原理和实现案例,JoinPoint,@Aspect,@Before,@AfterReturning

DAY25.2 Java核心基础 Spring两大核心&#xff1a;Ioc和Aop IOC Ioc容器&#xff1a;装载bean的容器&#xff0c;自动创建bean 三种方式&#xff1a; 1、基于xml配置&#xff1a;通过在xml里面配置bean&#xff0c;然后通过反射机制创建bean&#xff0c;存入进Ioc容器中 …

[解决conda创建新的虚拟环境没用python的问题]

问题复现 使用conda create -n env的时候&#xff0c;在对应的虚拟环境的文件里面找不到对应的python文件 为什么 首先&#xff0c;我们来看一下创建环境时的触发链路&#xff1a; 这表明当前环境中找不到Python可执行文件。 解决方法 所以很明显&#xff0c;我们需要指定…

【C++】控制台小游戏

移动&#xff1a;W向上&#xff0c;S上下&#xff0c;A向左&#xff0c;D向右 程序代码&#xff1a; #include <iostream> #include <conio.h> #include <windows.h> using namespace std;bool gameOver; const int width 20; const int height 17; int …

配合本专栏前端文章对应的后端文章——从模拟到展示:一步步搭建传感器数据交互系统

对应文章&#xff1a;进一步完善前端框架搭建及vue-konva依赖的使用&#xff08;Vscode&#xff09;-CSDN博客 目录 一、后端开发 1.模拟传感器数据 2.前端页面呈现数据后端互通 2.1更新模拟传感器数据程序&#xff08;多次请求&#xff09; 2.2&#x1f9e9; 功能目标 …

springboot IOC

springboot IOC IoC Inversion of Control Inversion 反转 依赖注入 DI &#xff08;dependency injection &#xff09; dependency 依赖 injection 注入 Qualifier 预选赛 一文带你快速理解JavaWeb中分层解耦的思想及其实现&#xff0c;理解 IOC和 DI https://zhuanlan.…

Ajax01-基础

一、AJAX 1.AJAX概念 使浏览器的XMLHttpRequest对象与服务器通信 浏览器网页中&#xff0c;使用 AJAX技术&#xff08;XHR对象&#xff09;发起获取省份列表数据的请求&#xff0c;服务器代码响应准备好的省份列表数据给前端&#xff0c;前端拿到数据数组以后&#xff0c;展…

生成树协议(STP)配置详解:避免网络环路的最佳实践

生成树协议&#xff08;STP&#xff09;配置详解&#xff1a;避免网络环路的最佳实践 生成树协议&#xff08;STP&#xff09;配置详解&#xff1a;避免网络环路的最佳实践一、STP基本原理二、STP 配置示例&#xff08;华为交换机&#xff09;1. 启用生成树协议2. 配置根桥3. 查…

面向 C 语言项目的系统化重构实战指南

摘要: 在实际开发中,C 语言项目往往随着功能演进逐渐变得混乱:目录不清、宏滥用、冗余代码、耦合高、测试少……面对这样的“技术债积累”,盲目大刀阔斧只会带来更多混乱。本文结合 C 语言的特点,从项目评估、目录规划、宏与内联、接口封装、冗余剔除、测试与 CI、迭代重构…

Python Pandas库简介及常见用法

Python Pandas库简介及常见用法 一、 Pandas简介1. 简介2. 主要特点&#xff08;一&#xff09;强大的数据结构&#xff08;二&#xff09;灵活的数据操作&#xff08;三&#xff09;时间序列分析支持&#xff08;四&#xff09;与其他库的兼容性 3.应用场景&#xff08;一&…

第十六届蓝桥杯复盘

文章目录 1.数位倍数2.IPv63.变换数组4.最大数字5.小说6.01串7.甘蔗8.原料采购 省赛过去一段时间了&#xff0c;现在复盘下&#xff0c;省赛报完名后一直没准备所以没打算参赛&#xff0c;直到比赛前两天才决定参加&#xff0c;赛前两天匆匆忙忙下载安装了比赛要用的编译器ecli…