题目
104. 二叉树的最大深度
难度:简单
分析:最简单的方法是使用递归,代码最少,速度也不慢;同时可以单独维持一个栈或是队列,使用深度优先搜索(DFS)或是宽度优先搜索(BFS)来得出答案。
不管是使用哪种方法,所有节点都必须被遍历,才能获得答案。
解法一:借助队列,宽度优先搜索
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
# 使用队列
from collections import deque
if not root:
return 0
depth = 0
my_que = deque()
my_que.append(root)
while my_que:
size = len(my_que)
depth += 1
for _ in range(size):
node = my_que.popleft()
if node.left: my_que.append(node.left)
if node.right: my_que.append(node.right)
return depth
运行结果:
解法二:借助栈,深度优先搜索
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
depth = 0
stack = [(root, 1)]
while stack:
node, level = stack.pop()
if node:
if not node.left and not node.right: # 叶节点
depth = max(depth, level)
continue
stack.append((node.right, level +1))
stack.append((node.left, level +1))
return depth
运行结果:
分析:
- 栈必须要把每一层的层次信息存储,不然无法区分同一层的节点;
- 更新答案深度信息的时候,不一定要判断是否叶节点。下面是深度优先的另一种解法。
不判断叶节点的解法:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:
return 0
depth = 0
stack = [(root, 1)]
while stack:
node, level = stack.pop()
if node:
depth = max(depth, level)
stack.append((node.right, level +1))
stack.append((node.left, level +1))
return depth
运行结果:
分析:
从运行时间来看,对于题目中给定的测试集,判断叶节点的方法更优。
假设被测试的树是一棵满二叉树,所有叶节点(假设为第n层)的左右子树节点不需要进栈,省去了 2 n 2^n 2n个节点的进栈和判断,同时省去了 2 n − 1 2^{n} - 1 2n−1次更新depth;而仅是增加了判断叶节点次数是 2 n − 1 2^n -1 2n−1。
因此,判断叶节点的方法更快便是理所当然了。
解法三:基于递归自上而下的求解
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
def depthCal(root, depth):
nonlocal ans
if not root:
return
if not root.left and not root.right: # 叶节点
ans = max(ans, depth)
depthCal(root.left, depth + 1)
depthCal(root.right, depth + 1)
ans = 0
depthCal(root, 1)
return ans
运行结果:
分析:
基于递归编写的解法,一般均需要单独定义一个子函数来完成递归,这样的目的是为了方便使用存储答案的ans变量,把答案传递出来。
解法四:基于递归自下而上的方法
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def maxDepth(self, root: TreeNode) -> int:
# 递归,自下向上
if not root:
return 0
left_depth = self.maxDepth(root.left)
right_depth = self.maxDepth(root.right)
return max(left_depth, right_depth) + 1
运行效果:
总结:
对于树的问题,使用递归是最简单且最直接的方式。
不过,使用迭代的方法,虽然代码变长了,但是运行时间有可能变短!
应该特别注意的是,我们自己维护一个栈或是队列时,叶子节点一定不要进栈或是进队列。