当前位置: 首页 > news >正文

【LeetCode热题100道笔记】二叉树的直径

题目描述

给你一棵二叉树的根节点,返回该树的 直径 。
二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。
两节点之间路径的 长度 由它们之间边数表示。

示例 1:
在这里插入图片描述
输入:root = [1,2,3,4,5]
输出:3
解释:3 ,取路径 [4,2,1,3] 或 [5,2,1,3] 的长度。

示例 2:
输入:root = [1,2]
输出:1

提示:
树中节点数目在范围 [1,104][1, 10^4][1,104]
-100 <= Node.val <= 100

思考一

思考一:基础递归(分治计算三类直径)

核心是分治思想:将二叉树直径拆解为“左子树内部直径”“右子树内部直径”“跨当前根节点的直径”三类,递归计算后取最大值。其中“跨根直径”需依赖子树深度(路径边数=左子树深度+右子树深度)。

算法过程

  1. 终止条件:若当前节点为null(空树),直径为0,直接返回0。

  2. 计算三类直径

    • 左子树内部直径:递归调用diameterOfBinaryTree(root.left),得到左子树自身的最长路径边数;
    • 右子树内部直径:递归调用diameterOfBinaryTree(root.right),得到右子树自身的最长路径边数;
    • 跨当前根节点的直径:先通过maxDepth函数计算左子树深度(节点数)和右子树深度,路径边数=左深度+右深度(因深度是节点数,边数=节点数-1,左右深度相加时“-1”抵消,直接求和即可);
  3. 返回最大值:取三类直径中的最大值,作为当前树的直径。

  4. 辅助函数maxDepth(计算子树深度)

    • 终止条件:空节点深度为0;
    • 递归计算左、右子树深度,当前节点深度=max(左深度, 右深度)+1(包含当前节点)。

时空复杂度

  • 时间复杂度:O(n²),n为二叉树节点总数。
    原因:对于每个节点,diameterOfBinaryTree递归会触发maxDepth递归,而maxDepth对每个子树需遍历所有节点。最坏情况下(链状树),总操作次数为O(n²)。
  • 空间复杂度:O(h),h为二叉树高度。
    原因:递归调用栈深度取决于树高,平衡树h=O(log n),链状树h=O(n)。

代码

/*** 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}*/
var diameterOfBinaryTree = function(root) {    if (!root) return 0;const maxLeft = diameterOfBinaryTree(root.left);const maxRight = diameterOfBinaryTree(root.right);const crossRoot = maxDepth(root.left) + maxDepth(root.right);return Math.max(maxLeft, maxRight, crossRoot);
};function maxDepth(root) {if (!root) return 0;return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}

思考二:优化递归(后序遍历避免重复计算)

基础递归的问题是maxDepth重复遍历节点(如计算父节点直径时,会重复计算子节点的深度)。优化思路是后序遍历:在计算子树深度的同时,同步更新全局最大直径(跨当前节点的直径=左深度+右深度),实现“一次遍历,双重用途”。

算法过程

  1. 初始化全局变量:定义ans存储最大直径,初始值为0(空树或单节点树的直径)。
  2. 后序遍历DFS函数(计算深度+更新直径)
    • 终止条件:若当前节点为null,深度为0,直接返回0;
    • 左子树处理:递归调用dfs(node.left),得到左子树深度maxLeftDepth
    • 右子树处理:递归调用dfs(node.right),得到右子树深度maxRightDepth
    • 更新最大直径:当前节点的跨根直径=左深度+右深度,若该值大于ans,则更新ans
    • 返回当前节点深度:当前节点深度=max(左深度, 右深度)+1(包含当前节点)。
  3. 触发遍历与返回结果:调用dfs(root)触发后序遍历,最终返回ans(全局最大直径)。

时空复杂度

  • 时间复杂度:O(n),n为二叉树节点总数。
    原因:后序遍历仅遍历每个节点一次,每个节点的操作(计算深度、更新直径)均为O(1),总操作次数为O(n),效率远高于基础递归。
  • 空间复杂度:O(h),h为二叉树高度。
    原因:递归调用栈深度取决于树高,平衡树h=O(log n),链状树h=O(n)(与基础递归一致,但避免了重复计算,时间效率更优)。

代码

/*** 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}*/
var diameterOfBinaryTree = function(root) {    if (!root) return 0;let ans = 0;const dfs = function(node) {if (!node) return 0;let maxLeftDepth = dfs(node.left);let maxRightDepth = dfs(node.right);ans = Math.max(ans, maxLeftDepth + maxRightDepth);return Math.max(maxLeftDepth, maxRightDepth) + 1;};dfs(root);return ans;
};

文章转载自:

http://v3xNlOqI.yzdth.cn
http://V4V0nHgU.yzdth.cn
http://Lg63cZQ2.yzdth.cn
http://E2HlnW3o.yzdth.cn
http://DtFmmnC5.yzdth.cn
http://ksiaypcy.yzdth.cn
http://1msfmzna.yzdth.cn
http://X47gfXJY.yzdth.cn
http://1OG3CjKu.yzdth.cn
http://J4lwtGRd.yzdth.cn
http://7BSHzPiy.yzdth.cn
http://xSKMcbMv.yzdth.cn
http://xxoqAV24.yzdth.cn
http://mQihJHUf.yzdth.cn
http://Rpl91A8c.yzdth.cn
http://6bGEQYmp.yzdth.cn
http://THP9RqGl.yzdth.cn
http://bFPYsZp3.yzdth.cn
http://MTWSaGwQ.yzdth.cn
http://CsCFapy3.yzdth.cn
http://zWq8RxtU.yzdth.cn
http://gqpbcLTg.yzdth.cn
http://C8U5CaiP.yzdth.cn
http://tmzfsBUn.yzdth.cn
http://4EKnKqQF.yzdth.cn
http://L3UhkjPB.yzdth.cn
http://i3gianvD.yzdth.cn
http://RjmDUlRU.yzdth.cn
http://HIMgVUdi.yzdth.cn
http://ctkXHP96.yzdth.cn
http://www.dtcms.com/a/370873.html

相关文章:

  • 2023年ASOC SCI2区TOP,改进元启发式算法+考虑医护人员技能水平的家庭健康护理路径规划,深度解析+性能实测
  • wpf之TextBlock
  • Docker安装Ubuntu搭建Android SDK编译环境
  • Golang中逃逸现象, 变量“何时栈?何时堆?”
  • 我用Claude Code 开发了一个浏览器插件
  • LRU 算法和 LFU 算法有什么区别?
  • Cursor安装使用 与 Cursor网页端登录成功,客户端怎么也登陆不上
  • vue + ant-design-vue + vuedraggable 实现可视化表单设计器
  • 未来教育行业的 Go 服务开发解决方案与实践
  • 为什么ubuntu大文件拷贝会先快后慢?
  • SQL-窗口函数
  • buuctf-鸡藕椒盐味,[NPUCTF2020]EzRSA,[WUSTCTF2020]大数计算
  • OpsManage 项目启动脚本与 Docker 配置深度分析
  • 智能制造——解读97页汽配行业ERP整体解决方案【附全文阅读】
  • LIO-SAM 算法从入门到部署实践
  • ES6 核心特性详解:从变量声明到函数参数优化
  • 云手机在企业办公中的作用
  • 2025高教社国赛数学建模C题参考论文(含模型和代码)
  • RPC 和 HTTP 的区别
  • 通过Idea 阿里插件快速部署java jar包
  • 在Ubuntu 22.04系统中无需重启设置静态IP地址
  • 数据结构中排序的时间、空间复杂度以及稳定性
  • 面试开发工程师需要做哪些准备
  • hot100-贪心算法(附图解思路)
  • 京东商品属性API数据解析:颜色、尺寸与材质
  • 附051.Kubernetes Karmada kubectl 插件部署联邦及使用
  • 从 Excel 趋势线到机器学习:拆解 AI 背后的核心框架​
  • 嵌入式学习笔记--Linux系统编程阶段--DAY06进程间通信-消息队列
  • 【Beetle RP2350】摇杆控制自定义角度旋转舵机
  • 波特率vs比特率