【LeetCode 热题100】深入理解二叉树结构变化与路径特性(力扣104 / 226 / 114 / 543)(Go语言版)

简介: 本博客深入探讨二叉树的深度计算、结构变换与路径分析,涵盖四道经典题目:104(最大深度)、226(翻转二叉树)、114(展开为链表)和543(二叉树直径)。通过递归与遍历策略(前序、后序等),解析每题的核心思路与实现方法。结合代码示例(Go语言),帮助读者掌握二叉树相关算法的精髓。下一讲将聚焦二叉树构造问题,欢迎持续关注!

🌲 深入理解二叉树结构变化与路径特性(力扣104 / 226 / 114 / 543)

在解题过程中,我们不仅要掌握二叉树的遍历方法,还需要理解它的结构特性。本篇博客将围绕二叉树的 深度计算、结构变换与路径分析 展开,涉及以下四道高频题:

  • [x] 104. 二叉树的最大深度
  • [x] 226. 翻转二叉树
  • [x] 114. 二叉树展开为链表
  • [x] 543. 二叉树的直径

📌 104. 二叉树的最大深度

✅ 题目描述:

给定一棵二叉树,找出其最大深度。最大深度是从根节点到最远叶子节点的最长路径上的节点数。

💡 解题思路:

这是一道非常经典的递归题。最大深度 = 左子树最大深度 与 右子树最大深度中的较大者 + 1。

我们可以使用 后序遍历(DFS),从叶子节点向上递归:

🧠 步骤解析:

  1. 递归终止条件:节点为空,返回0。
  2. 分别递归计算左右子树的最大深度。
  3. 当前节点的最大深度 = max(左,右) + 1。

💻 Go 实现:

func maxDepth(root *TreeNode) int {
   
    if root == nil {
   
        return 0
    }
    left := maxDepth(root.Left)
    right := maxDepth(root.Right)
    return max(left, right) + 1
}

📌 226. 翻转二叉树

✅ 题目描述:

翻转一棵二叉树,即左右子树交换。

示例:

输入:     4
         / \
        2   7
       / \ / \
      1  3 6  9
输出:     4
         / \
        7   2
       / \ / \
      9  6 3  1

💡 解题思路:

本质是递归地交换左右子树,可以用前序遍历来交换每个节点的左右子树。

🧠 步骤解析:

  1. 如果当前节点为 nil,返回 nil。
  2. 递归翻转左右子树。
  3. 交换左右子树。

💻 Go 实现:

func invertTree(root *TreeNode) *TreeNode {
   
    if root == nil {
   
        return nil
    }
    root.Left, root.Right = invertTree(root.Right), invertTree(root.Left)
    return root
}

📌 114. 二叉树展开为链表

✅ 题目描述:

将二叉树原地展开为一个单链表,使用前序遍历顺序,即所有右指针指向下一个节点,左指针置空。

💡 解题思路:

需要在原地修改树结构,我们可以借助 后序遍历 反向处理。

  • 倒着处理每个节点,将右子树先展开,再左子树展开,然后将当前节点的右指针指向上一个访问节点(类似于链表的前插操作)。

🧠 步骤解析(后序遍历 + 记录上一个节点):

  1. 先递归右子树,再递归左子树。
  2. 每次处理当前节点时,将其右指针指向前一个访问的节点(pre),左指针置空。
  3. 更新 pre 为当前节点。

💻 Go 实现:

var prev *TreeNode

func flatten(root *TreeNode) {
   
    if root == nil {
   
        return
    }
    flatten(root.Right)
    flatten(root.Left)
    root.Right = prev
    root.Left = nil
    prev = root
}

📌 543. 二叉树的直径

✅ 题目描述:

给定一棵二叉树,计算它的直径。直径是任意两个节点之间的最长路径,路径长度是节点数之差。

💡 解题思路:

路径可能穿过某个节点的左右子树,因此我们可以在计算深度时顺便计算当前节点左右深度之和,并维护最大值。

🧠 步骤解析(递归 + 回溯):

  1. 定义一个全局变量 res,记录最长路径。
  2. 在递归函数中,分别计算左右子树深度。
  3. 更新 res = max(res, left + right)
  4. 每次返回左右子树中最大深度 + 1。

💻 Go 实现:

var res int

func diameterOfBinaryTree(root *TreeNode) int {
   
    res = 0
    dfs(root)
    return res
}

func dfs(root *TreeNode) int {
   
    if root == nil {
   
        return 0
    }
    left := dfs(root.Left)
    right := dfs(root.Right)
    res = max(res, left+right)
    return max(left, right) + 1
}

🧠 小结与思考

题号 关键词 思维方法 特点
104 最大深度 后序遍历 求树高的典型题目
226 翻转结构 前序递归 每层交换左右子树
114 展开链表 后序遍历 倒序拼接前序路径
543 最大路径 递归+回溯 求路径最大值

📌 总结

  • 熟练掌握递归遍历策略(前序、中序、后序),在结构变化题中尤为重要。
  • 遇到路径相关问题时,可结合深度计算回溯策略
  • 在链表化或结构修改题目中,注意是否需要原地修改、是否可以使用辅助变量。

✍️ 下一篇我们将讨论“二叉树的构造”相关问题(105 & 108),包括如何根据前序中序构造树,以及如何构造平衡 BST。敬请期待!

如果这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐、关注 💻!持续更新 LeetCode 高频题详解 🚀🌲

目录
相关文章
|
3月前
|
存储 监控 算法
基于 Go 语言跳表结构的局域网控制桌面软件进程管理算法研究
针对企业局域网控制桌面软件对海量进程实时监控的需求,本文提出基于跳表的高效管理方案。通过多级索引实现O(log n)的查询、插入与删除性能,结合Go语言实现并发安全的跳表结构,显著提升进程状态处理效率,适用于千级进程的毫秒级响应场景。
197 15
|
4月前
|
存储 监控 算法
企业电脑监控系统中基于 Go 语言的跳表结构设备数据索引算法研究
本文介绍基于Go语言的跳表算法在企业电脑监控系统中的应用,通过多层索引结构将数据查询、插入、删除操作优化至O(log n),显著提升海量设备数据管理效率,解决传统链表查询延迟问题,实现高效设备状态定位与异常筛选。
154 3
|
4月前
|
存储 Java 编译器
对比Java学习Go——程序结构与变量
本节对比了Java与Go语言的基础结构,包括“Hello, World!”程序、代码组织方式、入口函数定义、基本数据类型及变量声明方式。Java强调严格的面向对象结构,所有代码需置于类中,入口方法需严格符合`public static void main(String[] args)`格式;而Go语言结构更简洁,使用包和函数组织代码,入口函数为`func main()`。两种语言在变量声明、常量定义、类型系统等方面也存在显著差异,体现了各自的设计哲学。
|
6月前
|
存储 安全 算法
Go语言泛型-泛型对代码结构的优化
Go语言自1.18版本引入泛型,极大提升了代码的通用性与可维护性。通过泛型,开发者可以减少重复代码、提高类型安全性,并增强程序的复用性和可读性。本文详细介绍了泛型在数据结构、算法及映射功能中的应用,展示了其在优化代码结构方面的优势。同时,Go编译器对泛型代码进行类型推导,确保运行时性能不受影响。合理使用泛型,有助于构建更加灵活高效的程序。
|
6月前
|
消息中间件 存储 算法
Go语言实战案例-自定义队列结构
本案例讲解如何使用 Go 语言通过结构体和切片实现自定义队列结构,涵盖入队、出队、查看队头元素及判空等基本操作,并提供完整示例代码与运行结果,适合初学者学习队列数据结构的实现与应用。
|
6月前
|
存储 算法 安全
Go语言实战案例-自定义栈结构
本案例详解如何用Go语言自定义栈结构,涵盖栈的压栈、弹栈、查看栈顶等基本操作,适合初学者掌握数据结构与算法基础。
|
7月前
|
Go
【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)
本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!
328 1
|
7月前
|
分布式计算 算法 Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本文讲解了两道经典的图论问题:**岛屿数量(LeetCode 200)** 和 **腐烂的橘子(LeetCode 994)**,分别通过 DFS/BFS 实现。在“岛屿数量”中,利用深度或广度优先搜索遍历二维网格,标记连通陆地并计数;“腐烂的橘子”则采用多源 BFS,模拟腐烂传播过程,计算最短时间。两者均需掌握访问标记技巧,是学习网格搜索算法的绝佳实践。
364 1
|
7月前
|
Go
【LeetCode 热题100】BFS/DFS 实战:岛屿数量 & 腐烂的橘子(力扣200 / 994 )(Go语言版)
本篇博客详细解析了三道经典的动态规划问题:198. 打家劫舍(线性状态转移)、279. 完全平方数与322. 零钱兑换(完全背包问题)。通过 Go 语言实现,帮助读者掌握动态规划的核心思想及其实战技巧。从状态定义到转移方程,逐步剖析每道题的解法,并总结其异同点,助力解决更复杂的 DP 问题。适合初学者深入理解动态规划的应用场景和优化方法。
260 0
|
7月前
|
算法 Go 索引
【LeetCode 热题100】回溯:括号生成 & 组合总和(力扣22 / 39 )(Go语言版)
本文深入解析了LeetCode上的两道经典回溯算法题:**22. 括号生成**与**39. 组合总和**。括号生成通过维护左右括号数量,确保路径合法并构造有效组合;组合总和则允许元素重复选择,利用剪枝优化搜索空间以找到所有满足目标和的组合。两者均需明确路径、选择列表及结束条件,同时合理运用剪枝策略提升效率。文章附有Go语言实现代码,助你掌握回溯算法的核心思想。
336 0