110.平衡二叉树
什么是平衡二叉树?
对于平衡二叉树中的任何一个节点,其左右子树的高度差不超过1。
前序、中序还是后序?
求二叉树的高度需要使用后序遍历,通过求出左右子树的高度后,返回给父节点。
举一个例子,根节点6的左子树高度是多少?
按照后序,首先定位到根节点6的左子节点2,以节点2为根节点的子树的高度是多少?
按照后序,首先定位到根节点2的左子节点0,以节点0为根节点的子树的高度是多少?
按照后序,以节点0为根节点的子树,没有左右子节点,接着访问中节点,也就是节点0,高度为1。
至此,以节点2为根节点的子树的左子树高度为1。
同理,以节点2为根节点的子树的右子树高度为2。
因此,根节点6的左子树的高度为 max(1, 2) + 1 = 3。
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
def height(node):
# 空节点,高度为0
if not node: return 0
# 递归计算左子树和右子树的高度
left_height = height(node.left)
right_height = height(node.right)
# 判断当前树是否平衡
# 如果左子树或者右子树不平衡,则当前树不平衡
# 如果左子树和右子树平衡,但高度差超过1,则当前树不平衡
# 如果当前树平衡,返回当前树的高度
if left_height == -1: return -1
if right_height == -1: return -1
if abs(left_height - right_height) > 1: return -1
return max(left_height, right_height) + 1
return height(root) != -1
# 我们可以看到,
# 对于一课树,需要先计算其左右子树的高度
# 接着才可以判断此树是否平衡
# 因此采用后序遍历
257.二叉树的所有路径
需要探索从根节点到每个叶子节点的所有可能路径。在这个过程中,递归地遍历树的每个节点,沿途记录路径。当我们到达一个叶子节点时,我们找到了一条完整的路径。此时,我们需要“回溯”以去探索其他分支,这就要求我们撤销之前的选择(即从当前路径中移除最近访问的节点),以便路径反映出新的探索方向。
由于需要返回从根节点到叶子结点的路径,自然会选择前序,从上至下依次遍历。
class Solution:
def binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
if not root:
return []
result = []
path = []
def traversal(node, path, result):
# 中
path.append(node.val)
# 到达叶子节点
if not node.left and not node.right:
result.append('->'.join(map(str, path)))
return
# 左
if node.left:
traversal(node.left, path, result)
path.pop() # 回溯
# 右
if node.right:
traversal(node.right, path, result)
path.pop()
traversal(root, path, result)
return result
404.左叶子之和
什么是左叶子?
1. 是叶子结点
2. 是其父节点的左孩子
因此要判断某节点是否为左叶子,需要遍历到其父节点,并满足以上两个条件。
class Solution:
def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:
if not root:
return 0
sum_left = 0
# 检查左子节点是否是叶子
if root.left and not root.left.left and not root.left.right:
sum_left += root.left.val
# 如果不是,递归遍历左子树
else:
sum_left += self.sumOfLeftLeaves(root.left)
# 递归遍历右子树
sum_left += self.sumOfLeftLeaves(root.right)
return sum_left