今日算法题:
题目

题解
# 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 0
left_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
- 9 的左是空 → 0;右是空 → 0;所以 9 的深度 =
-
去算
3
的右子树(根=20):- 20 的左(15)深度 =
1
;右(7)深度 =1
;所以 20 的深度 =1 + max(1,1) = 2
- 20 的左(15)深度 =
-
最后
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
表示"没有孩子"。 -
链接关系靠
left
和right
这两个"引用变量"落实:比如root.left = node9
就把根的左指针指向node9
。
那么这段代码怎么就能直接表示成一棵二叉树呢?
我并没有任何手动的代码实现,我只能看到测试用例得有一串数组 ,直接看代码是无法变成树的呀?也就无法调用这些left
、right
的方法实现树的左子树右子树的调用。
答案是:
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 = val
self.left = left
self.right = right
from collections import deque
def build_tree(values):
if not values:
return None
root = TreeNode(values[0])
queue = deque([root])
i = 1
while queue and i < len(values):
node = queue.popleft()
if values[i] is not None:
node.left = TreeNode(values[i])
queue.append(node.left)
i += 1
if i < len(values) and values[i] is not None:
node.right = TreeNode(values[i])
queue.append(node.right)
i += 1
return 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 0
queue = 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。