二叉树问题的解题思路
⼆叉树题⽬的递归解法可以分两类思路,第⼀类是遍历⼀遍⼆叉树得出答案,第⼆类是通过分解问题计算出答案,这两类思路分别对应着 回溯算法核⼼框架 和 动态规划核⼼框架。下面我将通过题104和543分别进行举例。
104. 二叉树的深度
解法:深度优先遍历(遍历框架)
该题可以通过遍历二叉树,对每个叶子节点所在深度进行判断,找到二叉树的最大深度。同样明确「要做什么」以及「什么时候做」。前者为当前遍历到的深度变化,后者为遍历到该节点时深度+1,遍历结束回退后深度-1
class Solution:
res = 0
depth = 0
def maxDepth(self, root: Optional[TreeNode]) -> int:
self.traverse(root)
return self.res
def traverse(self, node):
if not node:
self.res = max(self.res, self.depth)
return
# 遍历思路求解
self.depth += 1
self.traverse(node.left)
self.traverse(node.right)
self.depth -= 1
解法2:深度优先遍历(分解问题思路)
该题同样可以用分解问题思路来求解,求以root为根节点的二叉树的最大深度,及分别求得左右子树的最大深度,再对它们之间的最大值+1即为该二叉树的最大深度。具体解法可参考下题。
543. 二叉树的直径
解法:深度优先遍历(分解问题思路)
对于以root节点为起点的路径,其长度可以等价为其左右子树的最大深度之和。例如对于下图,以2为起点,其路径为2(左子树最大深度)+3(右子树最大深度)等于5。
所以求以任一节点为起点的路径,可以分解为先求其左子树和右子树的最大深度,再进行求和。
而求解二叉树的直径,要对以其中所有节点为起点的情况进行遍历,找到最长路径。同样,需要明确每个节点「要做什么」以及「什么时候做」,前者为求以其为起点的路径长度。后者为后序遍历,需要先求得其左右子树的最大深度。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def diameterOfBinaryTree(self, root: TreeNode) -> int:
self.result = 0
def maxDepth(node):
if not node:
return 0
# 分解思路求解,该问题通过遍历一遍二叉树不可以解决,需要从子问题来推导。
left = maxDepth(node.left)
right = maxDepth(node.right)
# print(left, right)
self.result = max(self.result, left + right)
return max(left, right) + 1
maxDepth(root)
return self.result
总结
综上,遇到⼀道⼆叉树的题⽬时的通⽤思考过程是:
是否可以通过遍历⼀遍⼆叉树得到答案?如果不能的话,是否可以定义⼀个递归函数,通过⼦问题(⼦树)的答案推导出原问题的答案?前者是节点遍历操作,后者是先操作子树,在推导原问题。
后续可以分别用上述两种思路对144. 二叉树的前序遍历进行求解,以此加深理解,体会它们之间的异同点。