文章目录
104. 二叉树的最大深度
- 深度:从根节点到该节点的最长简单路径边的条数(深度从0开始)或者节点数(深度从1开始)
- 深度从根节点开始计算,子节点深度取决于父节点的深度,信息的流向决定了使用前序遍历
- 高度:从该节点到叶子节点的最长简单路径边的条数(深度从0开始)或者节点数(高度从1开始)
- 高度从叶子节点开始计算,父节点的高度取决于子节点的高度,信息的流向决定了使用后序遍历
高度与深度的联系:根节点的高度就是二叉树的最大深度
前序遍历(自己的解法:深度)
class Solution:
def depth(self, node: Optional[TreeNode], level: int) -> int:
if node == None:
return level
# middle
left_depth = self.depth(node.left, level + 1) # left
right_depth = self.depth(node.right, level + 1) # right
return max(left_depth, right_depth)
def maxDepth(self, root: Optional[TreeNode]) -> int:
return self.depth(root, 0)
后序遍历(高度)
class Solution:
def height(self, node: Optional[TreeNode]) -> int:
if node == None:
return 0
left_height = self.height(node.left) # left
right_height = self.height(node.right) # right
return max(left_height, right_height) + 1 # middle
def maxDepth(self, root: Optional[TreeNode]) -> int:
return self.height(root)
559. n叉树的最大深度
自己的前序遍历解法,和二叉树的几乎一模一样。
class Solution:
def depth(self, node: 'Node', level: int) -> int:
if node == None:
return level
records = [level + 1]
for child in node.children:
records.append(self.depth(child, level + 1))
return max(records)
def maxDepth(self, root: 'Node') -> int:
return self.depth(root, 0)
111. 二叉树的最小深度
最小深度:从根节点到叶子节点的最短路径上的节点数量。(注意是叶子节点!!)
这个定义和根节点的高度非常相似(高度是根节点到叶子节点的最远路径),所以还是可以后序遍历,从而得到最小深度。相比于前序,后序的解法会稍简洁一些。
要小心的是对于空节点的处理,在后序解法中 None 是没可能成为叶子节点的,但却拥有最小的深度。
前序遍历(自己的解法:深度)
class Solution:
def depth(self, node: Optional[TreeNode], level: int, records: list) -> None:
if node.left == None and node.right == None:
records.append(level + 1)
if node.left != None:
self.depth(node.left, level + 1, records)
if node.right != None:
self.depth(node.right, level + 1, records)
def minDepth(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
records = []
self.depth(root, 0, records)
return min(records)
后序遍历(根节点的最小“高度“)
class Solution:
def height(self, node: Optional[TreeNode]) -> int:
if node == None:
return 0
left_height = self.height(node.left) # left
right_height = self.height(node.right) # right
# middle
if node.left != None and node.right == None: # exclude the "None" node
return 1 + left_height
if node.left == None and node.right != None:
return 1 + right_height
return 1 + min(left_height, right_height)
def minDepth(self, root: Optional[TreeNode]) -> int:
return self.height(root)
222. 完全二叉树的节点个数
看似非常模板化的一道题,任何遍历方式都能够得到所有节点然后计数。但题目要求优于 O ( n ) O(n) O(n) 的算法,就必须利用完全二叉树的特征:除了最后一层都是满的,最后一层的节点尽可能靠左分布。
对于完全二叉树而言,寻找到满二叉子树即可通过公式直接计算该树内的节点数量,并向父节点传递。只需要得到左右外侧的深度即可判断,单次搜索的复杂度为 O ( log n ) O(\log{n}) O(logn)。对于非满二叉子树,递归会逐渐将其拆成若干满二叉子树和单独节点。
这道题的递归终止条件比较复杂,当找到了满二叉子树的时候也应该直接返回(这也是低复杂度的来源,跳过了搜索所有满二叉子树的内部节点)。
- 时间复杂度: O ( log n × log n ) O(\log{n} \times \log{n}) O(logn×logn)
- 空间复杂度: O ( log n ) O(\log{n}) O(logn)
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
if root == None:
return 0
# check whether this (sub)tree is full
left_depth = right_depth = 0
left_node = root.left
right_node = root.right
while (left_node != None):
left_node = left_node.left
left_depth += 1
while (right_node != None):
right_node = right_node.right
right_depth += 1
# full tree case: directly return
if left_depth == right_depth:
return (2**(left_depth+1)) - 1 # equivalent to (2<<left_depth) - 1, fancy!
# not a full tree, go into recursion
print("haha")
return self.countNodes(root.left) + self.countNodes(root.right) + 1