Leetcode 662: 二叉树最大宽度

Leetcode 662: 二叉树最大宽度 是一道考察树的层序遍历和位编号思想的经典题目。其目标是找到二叉树的每一层的最大宽度,宽度定义为:最左节点和最右节点间的节点数(包含这两个节点,中间可以有空节点)


题目描述

  • 给定一个二叉树的根节点 root,返回其最大宽度
  • “宽度”定义为:
    • 每层最左节点(即层级中最左非空节点)到最右节点之间节点的数目。
    • 如果同一层只有一个非空节点,则宽度为 1。

解法 1:层序遍历 + 队列 (广度优先搜索 BFS)

思路
  • 维护位置信息
    • 使用广度优先遍历 BFS,同时为每个节点分配一个基于完全二叉树的编号。根节点的编号为 1,左孩子为 2 * x,右孩子为 2 * x + 1
    • 每层的宽度可通过计算该层最右节点和最左节点对应编号的差值 width = right - left + 1
  • 层序遍历逐层更新最大宽度
    • 使用一个队列,存储每层节点和它们的编号 (node, index)
    • 遍历每一层时,记录最左节点和最右节点对应的编号,然后计算宽度,更新最大值。

代码模板
class Solution {public int widthOfBinaryTree(TreeNode root) {if (root == null) return 0;// 队列存节点和它的"编号" (1-based index for position)Deque<Pair<TreeNode, Integer>> queue = new ArrayDeque<>();queue.offer(new Pair<>(root, 1));int maxWidth = 0;while (!queue.isEmpty()) {int size = queue.size();int left = queue.peekFirst().getValue(); // 当前层最左的编号int right = queue.peekLast().getValue(); // 当前层最右的编号maxWidth = Math.max(maxWidth, right - left + 1);for (int i = 0; i < size; i++) {Pair<TreeNode, Integer> pair = queue.poll();TreeNode node = pair.getKey();int index = pair.getValue();// 添加左右孩子到队列if (node.left != null) {queue.offer(new Pair<>(node.left, 2 * index));}if (node.right != null) {queue.offer(new Pair<>(node.right, 2 * index + 1));}}}return maxWidth;}
}

复杂度分析
  • 时间复杂度:O(n)
    • 每个节点入队和出队各一次,总的时间复杂度为 O(n)。
  • 空间复杂度:O(n)
    • 最差情况下,队列存储所有节点 (如完全二叉树的某一层)。

解法 2:DFS 深度优先搜索 + 位编号

思路
  • 递归方法:
    • 对每个节点,按照广度优先编号规则计算其位置索引,然后递归处理左、右子树。
    • 使用一个 Map<Integer, Integer> 记录每层的最左节点编号。
    • 对每个节点,计算当前宽度:width = currentIndex - leftIndexAtCurrentLevel + 1
    • 同时在递归过程中维护最大宽度值。

关键步骤
  1. 递归传递 当前节点的编号层级信息
  2. 递归更新宽度
    • 如果是当前层第一个访问的节点,记录它的编号为该层的最左编号。
    • 更新当前层宽度,调整全局最大宽度。
  3. 对左右子树分别递归处理:
    • 左子树位置编号为 2 * currentIndex
    • 右子树位置编号为 2 * currentIndex + 1

代码模板
class Solution {public int widthOfBinaryTree(TreeNode root) {Map<Integer, Integer> leftMostPos = new HashMap<>(); // 每层最左节点的编号return dfs(root, 0, 1, leftMostPos);}private int dfs(TreeNode node, int depth, int index, Map<Integer, Integer> leftMostPos) {if (node == null) return 0;// 如果当前层是第一次访问,记录最左位置leftMostPos.computeIfAbsent(depth, x -> index);// 当前宽度 = 当前节点的编号 - 当前层最左编号 + 1int currentWidth = index - leftMostPos.get(depth) + 1;// 递归求左右子树的最大宽度int leftWidth = dfs(node.left, depth + 1, 2 * index, leftMostPos);int rightWidth = dfs(node.right, depth + 1, 2 * index + 1, leftMostPos);// 返回当前层和左右子树的最大宽度return Math.max(currentWidth, Math.max(leftWidth, rightWidth));}
}

复杂度分析
  • 时间复杂度:O(n)
    • 每个节点只访问一次。
  • 空间复杂度:O(h)
    • 递归调用栈的最大深度为树的高度,最差情况为 O(n)(如链状树)。

解法 3:BFS 优化(直接计算宽度)

优化点

相比解法 1 的队列实现,这里省略使用 Pair 来记录编号数,直接在每层中计算 startend 的编号即可。


代码模板
class Solution {public int widthOfBinaryTree(TreeNode root) {if (root == null) return 0;Deque<TreeNode> nodeQueue = new ArrayDeque<>();Deque<Integer> indexQueue = new ArrayDeque<>();nodeQueue.offer(root);indexQueue.offer(1);int maxWidth = 0;while (!nodeQueue.isEmpty()) {int size = nodeQueue.size();int startIndex = indexQueue.peekFirst();int endIndex = indexQueue.peekLast();maxWidth = Math.max(maxWidth, endIndex - startIndex + 1);for (int i = 0; i < size; i++) {TreeNode currNode = nodeQueue.poll();int currIndex = indexQueue.poll();if (currNode.left != null) {nodeQueue.offer(currNode.left);indexQueue.offer(2 * currIndex);}if (currNode.right != null) {nodeQueue.offer(currNode.right);indexQueue.offer(2 * currIndex + 1);}}}return maxWidth;}
}

复杂度分析
  • 时间复杂度:O(n)
    • 每个节点入队、出队各一次。
  • 空间复杂度:O(n)
    • 队列需要存储某一层的所有节点。

快速AC策略

  1. 选择解法:
    • 如果面试中强调代码可读性:写BFS 队列解法(解法 1)。清晰易懂,是优先选择。
    • 如果数据规模中等且需要最优效率:写DFS 解法(解法 2)。递归代码更简洁,但需注意递归深度。
  2. 注意特殊情况
    • 输入为 null 的边界。
    • 确保编号的范围不会超过 int 取值范围(通常树的层级不会超过几十层)。
  3. 模板熟练度
    • BFS 模板:尽量减少额外的数据结构操作(比如 Pair)。
    • DFS 模板:确保层编号和位编号一致处理。

通过以上解法分析与模板准备,可以快速完成这道题并 AC!

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

250301-OpenWebUI配置DeepSeek-火山方舟+硅基流动+联网搜索+推理显示

A. 最终效果 B. 火山方舟配置&#xff08;一定要点击添加&#xff09; C. 硅基流动配置&#xff08;最好要点击添加&#xff0c;否则会自动弹出所有模型&#xff09; D. 联网搜索配置 E. 推理过程显示 默认是没有下面的推理过程的显示的 F. SearXNG配置 注意&#xff1a;此…

阿里云物联网获取设备属性api接口:QueryDevicePropertyData

阿里云物联网接口&#xff1a;QueryDevicePropertyData 说明&#xff1a;调用该接口查询指定设备或数字孪生节点&#xff0c;在指定时间段内&#xff0c;单个属性的数据 比如提取上传到物联网的温度数据 api文档&#xff1a;QueryDevicePropertyData_物联网平台_API文档-阿里…

算法系列之动态规划

动态规划&#xff08;Dynamic Programming&#xff0c;简称DP&#xff09;是一种用于解决复杂问题的算法设计技术。它通过将问题分解为更小的子问题&#xff0c;并存储这些子问题的解来避免重复计算&#xff0c;从而提高算法的效率。本文将介绍动态规划的基本概念、适用场景、复…

Linux系列:如何用 C#调用 C方法造成内存泄露

一&#xff1a;背景 1. 讲故事 好久没写文章了&#xff0c;还是来写一点吧&#xff0c;今年准备多写一点 Linux平台上的东西&#xff0c;这篇从 C# 调用 C 这个例子开始。在 windows 平台上&#xff0c;我们常常在 C 代码中用 extern "C" 导出 C风格 的函数&#x…

1.2.3 使用Spring Initializr方式构建Spring Boot项目

本实战概述介绍了如何使用Spring Initializr创建Spring Boot项目&#xff0c;并进行基本配置。首先&#xff0c;通过Spring Initializr生成项目骨架&#xff0c;然后创建控制器HelloController&#xff0c;定义处理GET请求的方法hello&#xff0c;返回HTML字符串。接着&#xf…

【音视频】H265解码Nalu后封装rtp包

概述 基于ZLM流媒体框架以及简单RTSP服务器开源项目分析总结&#xff0c;相关源码参考以下链接 H265-rtp提取Nalu逻辑 通过rtsp流地址我们可以获取视频流中的多个rtp包&#xff0c;其中每个RTP包中又会包含一个或者多个Nalu&#xff0c;将其提取处理 总体逻辑分析 核心逻辑在…

03.03 QT

1.在注册登录的练习里面&#xff0c;追加一个QListwidget 项目列表 要求:点击注册之后&#xff0c;将账号显示到 1istwidget上面去 以及&#xff0c;在listwidget中双击某个账号的时候&#xff0c;将该账号删除 Widget.h: #ifndef WIDGET_H #define WIDGET_H#include <QWi…

【星云 Orbit • STM32F4】04.一触即发:GPIO 外部中断

【星云 Orbit- • STM32F4】04. 一触即发&#xff1a;外部中断控制 摘要 本文详细介绍了如何使用STM32F407微控制器的HAL库实现外部中断功能。通过配置GPIO引脚作为外部中断源&#xff0c;并在中断回调函数中处理按键事件&#xff0c;实现了按键控制LED状态翻转的功能。本文旨…

(新版本onenet)stm32+esp8266/01s mqtt连接onenet上报温湿度和远程控制(含小程序)

物联网实践教程&#xff1a;微信小程序结合OneNET平台MQTT实现STM32单片机远程智能控制 远程上报和接收数据——汇总 前言 之前在学校获得了一个新玩意&#xff1a;ESP-01sWIFI模块&#xff0c;去搜了一下这个小东西很有玩点&#xff0c;远程控制LED啥的&#xff0c;然后我就想…

并发编程(线程基础)面试题及原理

1. 进程与线程 1.1 进程 程序由指令和数据组成&#xff0c;但这些指令要运行&#xff0c;数据要读写&#xff0c;就必须将指令加载至CPU&#xff0c;数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。 当一个程序被运…

基于开源库编写MQTT通讯

目录 1. MQTT是什么&#xff1f;2. 开发交互UI3. 服务器核心代码4. 客户端核心代码5. 消息订阅与发布6. 通讯测试7. MQTT与PLC通讯最后. 核心总结 1. MQTT是什么&#xff1f; MQTT&#xff08;Message Queuing Terlemetry Transport&#xff09;消息队列遥测协议&#xff1b;是…

vector习题

完数和盈数 题目 完数VS盈数_牛客题霸_牛客网 一个数如果恰好等于它的各因子(该数本身除外)之和&#xff0c;如&#xff1a;6321。则称其为“完数”&#xff1b;若因子之和大于该数&#xff0c;则称其为“盈数”。 求出2到60之间所有“完数”和“盈数”。 输入描述&#xff…

vscode通过ssh远程连接(linux系统)不能跳转问题

1.问题描述 unbantu中的vscode能够通过函数跳转到函数定义&#xff0c;而windows通过ssh连接unbantu的vscode却无法跳转 2.原因&#xff1a; 主要原因是这里缺少插件&#xff0c;这里是unbantu给主机的服务器&#xff0c;与ubantu本地vscode插件相互独立&#xff0c;能否跳转…

神经网络 - 激活函数(Swish函数、GELU函数)

一、Swish 函数 Swish 函数是一种较新的激活函数&#xff0c;由 Ramachandran 等人在 2017 年提出&#xff0c;其数学表达式通常为 其中 σ(x) 是 Sigmoid 函数&#xff08;Logistic 函数&#xff09;。 如何理解 Swish 函数 自门控特性 Swish 函数可以看作是对输入 x 进行“…

安全运营的“黄金4小时“:如何突破告警疲劳困局

在当今复杂多变的网络安全环境中&#xff0c;安全团队面临着前所未有的挑战。尤其是面对高级持续性威胁&#xff08;APT&#xff09;时&#xff0c;最初的“黄金4小时”成为决定成败的关键窗口。在这段时间内&#xff0c;快速而准确地响应可以极大地降低损失&#xff0c;然而&a…

【Pytest】setup和teardown的四个级别

文章目录 1.setup和teardown简介2.模块级别的 setup 和 teardown3.函数级别的 setup 和 teardown4.方法级别的 setup 和 teardown5.类级别的 setup 和 teardown 1.setup和teardown简介 在 pytest 中&#xff0c;setup 和 teardown 用于在测试用例执行前后执行一些准备和清理操…

傅里叶分析

傅里叶分析之掐死教程&#xff08;完整版&#xff09;更新于2014.06.06 要让读者在不看任何数学公式的情况下理解傅里叶分析。 傅里叶分析不仅仅是一个数学工具&#xff0c;更是一种可以彻底颠覆一个人以前世界观的思维模式。但不幸的是&#xff0c;傅里叶分析的公式看起来太复…

matlab 四维数据可视化(已解决)

虽然这不是传统意义上的“4维可视化”&#xff0c;但你可以通过在三维空间中表示两个维度来间接展示4维数据。例如&#xff0c;你可以使用颜色来表示第四个维度。 clc clear close all% 假设X, Y, Z为你的三维数据&#xff0c;C为第四维数据 X rand(100, 1); Y rand(100, 1);…

MAC 本地搭建部署 dify(含 github访问超时+Docker镜像源拉取超时解决方案)

目录 一、什么是 dify&#xff1f; 二、安装 docker 1. 什么是 docker&#xff1f; 2. docker下载地址 三、安装 dify 1. dify下载地址 2.可能遇到问题一&#xff1a; github访问超时 3.下载后完成解压 4.进入到 cmd 终端环境&#xff0c;执行下面三个命令 5.可能遇到…

rustup-init.exe 安装缓慢的解决办法

首先在rust官网下载安装程序&#xff0c;官网下载的 rustup-init.exe 下载慢&#xff0c;安装慢&#xff0c;或者直接卡死。 下载安装程序在本地&#xff0c;使用国内镜像加速 Rust 更新与下载。 使用国内镜像源&#xff1a;在 rustup-init.exe 程序文件夹下使用 PowerShell 中…