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

hot100 之104-二叉树的最大深度(递归+二叉树)

今日算法题:

题目

题解

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):def maxDepth(self, root):if not root:return 0left_depth = self.maxDepth(root.left)right_depth = self.maxDepth(root.right)return 1 + max(left_depth,right_depth) 

核心思路

语法小贴士

  • if not root::在 Python 里,None 被当作“假”,所以“如果没有节点就返回 0”。

  • 函数调用自己就叫递归:self.maxDepth(root.left)

  • max(a, b) 取较大值。

  • return 返回该子树的最大深度给“上一层”调用者。

这段递归到底怎么“跑”的?(以根=3为例)

  • 去算 3 的左子树(根=9):

    • 9 的左是空 → 0;右是空 → 0;所以 9 的深度 = 1 + max(0,0) = 1

  • 去算 3 的右子树(根=20):

    • 20 的左(15)深度 = 1;右(7)深度 = 1;所以 20 的深度 = 1 + max(1,1) = 2

  • 最后 3 的深度 = 1 + max(1,2) = 3

该方法时间复杂度是 O(n)(每个节点访问一次)。

空间复杂度:

  • 递归:最坏 O(h)(h=树高,最坏退化链表时 O(n))。

体现知识点

二叉树节点实现

力扣里通常给这个结构(或等价):

class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = val     # 当前节点存的数self.left = left   # 左孩子(是另一个 TreeNode 或 None)self.right = right # 右孩子(是另一个 TreeNode 或 None)
  • None 表示“没有孩子”。

  • 链接关系靠 leftright 这两个“引用变量”落实:比如 root.left = node9 就把根的左指针指向 node9

那么这段代码怎么就能直接表示成一棵二叉树呢?

我并没有任何手动的代码实现,我只能看到测试用例得有一串数组,直接看代码是无法变成树的呀?也就无法调用这些leftright的方法实现树的左子树右子树的调用。

答案是:

LeetCode/测试平台帮你做了

在 LeetCode 上,题目输入通常是 [3,9,20,null,null,15,7] 这样的数组。

👉 平台在你代码跑之前,会先把输入数组“转成一棵二叉树”,这就是测试用例的底层逻辑。
它内部其实就是写了类似的代码:

# 假设输入是 [3,9,20,null,null,15,7]
root = TreeNode(3)
root.left = TreeNode(9)
root.right = TreeNode(20)
root.right.left = TreeNode(15)
root.right.right = TreeNode(7)

只是这些赋值的步骤你看不到,是平台帮你造好了这棵树,然后把 root 传给你的函数

所以你在函数里直接用 root,就能拿到已经链接好的二叉树。

平台(LeetCode)的情况
  • 你在 解题函数 里拿到的参数是 root: TreeNode,它已经是一棵二叉树的根节点。

  • 之所以能这样,是因为 LeetCode 在测试用例的底层,把输入的数组 [3,9,20,null,null,15,7] 转换成了一棵树,然后才把树的 root 传给你的函数。

  • 所以你才会感觉“我啥都没写,怎么树就有了”。

👉 本质上是 平台替你写好了建树的逻辑

本地自己写代码的情况

如果你直接在本地写:

def maxDepth(root):# 求树的最大深度...root = [3,9,20,None,None,15,7]   # 直接传数组
print(maxDepth(root))

❌ 这是不行的。
因为 root 只是一个 Python 列表,根本不是 TreeNode 对象,更没有 .left.right 这些属性。
你调用 root.left 会直接报错:AttributeError: 'list' object has no attribute 'left'

若要在本地执行正确做法

如果你在本地写,就要自己实现“数组 → 二叉树”的过程(LeetCode 帮你隐藏的那一步)。
比如用我刚才给的 build_tree 函数:

class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightfrom collections import dequedef build_tree(values):if not values:return Noneroot = TreeNode(values[0])queue = deque([root])i = 1while queue and i < len(values):node = queue.popleft()if values[i] is not None:node.left = TreeNode(values[i])queue.append(node.left)i += 1if i < len(values) and values[i] is not None:node.right = TreeNode(values[i])queue.append(node.right)i += 1return root# 本地用数组造树
root = build_tree([3,9,20,None,None,15,7])

这样 root 就是一个真正的二叉树对象了,接下来你写的 maxDepth(root) 才能跑。

过程困难

逻辑问题:

就是上面二叉树的理解

优化解法

还有一种解法是用层序遍历的方法解,但是使用递归的方法易于理解也易于实现。

BFS(队列)版本——逐行解释

from collections import deque  # deque 是高效队列class Solution:def maxDepth(self, root: 'TreeNode') -> int:if not root:return 0queue = deque([root])  # 初始队列放入根depth = 0              # 已经走过的层数while queue:           # 只要这一层还有节点depth += 1         # 新的一层开始了for _ in range(len(queue)):  # 把“当前层”的节点个数先记下来node = queue.popleft()   # 逐个取出这一层的节点if node.left:queue.append(node.left)   # 把下一层的孩子放进去if node.right:queue.append(node.right)return depth

语法小贴士

  • deque([...]):创建一个队列,popleft() 从左边弹出,表示“出队”。

  • while queue::队列非空就继续。

  • for _ in range(len(queue))::这一招很关键!

    • len(queue) 是“当前层”的节点数;

    • 用它控制 for 循环次数,确保这一轮只处理这一层

    • _ 表示“这个变量我不打算用”。

按层走一遍(你的例子)

  • 队列:[3] → 处理 1 个节点(3),加入它的孩子 9、20;深度=1

  • 队列:[9,20] → 处理 2 个节点(9、20),加入 20 的孩子 15、7;深度=2

  • 队列:[15,7] → 处理 2 个节点(15、7),没有孩子可加;深度=3

  • 队列空 → 结束,返回 3 ✅

复杂度与选择

  • 两种方法时间复杂度都是 O(n)(每个节点访问一次)。

  • 空间复杂度:

    • 递归:最坏 O(h)(h=树高,最坏退化链表时 O(n))。

    • BFS:最坏 O(w)(w=某一层的最大节点数,满二叉树中部层最宽)。

怎么选?

  • 代码简洁→选递归;

  • 想按层处理或不想用递归→选 BFS。

http://www.dtcms.com/a/348929.html

相关文章:

  • 分治--常见面试问题
  • 协程解决了什么问题
  • 中级统计师-统计实务-第一章 综述
  • CPTS-Agile (Werkzeug / Flask Debug)
  • 服务器加密算法
  • HMM+viterbi学习
  • Trip Footprint旅行足迹App
  • Windows在资源管理器地址栏输入CMD没反应
  • MATLAB 数值计算进阶:微分方程求解与矩阵运算高效方法
  • 伯朗特功率分析仪通过Modbus转Profinet网关与工业以太网集成案例
  • RunningHub - 基于ComfyUI的云端AI创作与应用平台
  • PID控制器的原理以及PID控制仿真
  • 离线签名协调器 Offline Signing Orchestrator(OSO)
  • 可视化-模块1-HTML-03
  • 图解SpringMVC工作流程,以及源码分析。
  • response对象的elapsed属性
  • 深度模块化剖析:构建一个健壮的、支持动态Cookie和代理的Python网络爬虫
  • Altium Designer 22使用笔记(9)---PCB布局、布线操作
  • halcon(一)一维码解码
  • 普元低代码开发平台:开启企业高效创新新征程
  • 刷题日记0824
  • 【AI论文】实习生-S1:一种科学多模态基础模型
  • 0824 MLIR和AST相关资料
  • 复杂工业场景识别率↑18.3%!陌讯多模态OCR算法实战解析
  • 虚幻引擎5(UE5)Android端游戏开发全流程指南:从环境配置到项目发布
  • Qt工具栏中图标槽函数没有响应的问题分析
  • 【JVM内存结构系列】三、堆内存深度解析:Java对象的“生存主场”
  • 【数据分享】地级市能源利用效率(超效率SBM、超效率CCR)(2006-2023)
  • Vue中 this.$emit() 方法详解, 帮助子组件向父组件传递事件
  • 纯血鸿蒙下的webdav库