LeetCode 662. 二叉树最大宽度
给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。
每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。
示例 1:
输入:
1
/ \
3 2
/ \ \
5 3 9
输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。
示例 2:
输入:
1
/
3
/ \
5 3
输出: 2
解释: 最大值出现在树的第 3 层,宽度为 2 (5,3)。
示例 3:
输入:
1
/ \
3 2
/
5
输出: 2
解释: 最大值出现在树的第 2 层,宽度为 2 (3,2)。
示例 4:
输入:
1
/ \
3 2
/ \
5 9
/ \
6 7
输出: 8
解释: 最大值出现在树的第 4 层,宽度为 8 (6,null,null,null,null,null,null,7)。
思路
由于我们需要将给定树中的每个节点都访问一遍,我们需要遍历树。我们可以用深度优先搜索或者宽度优先搜索将树遍历。
这个问题中的主要想法是给每个节点一个 position 值,如果我们走向左子树,那么 position -> position x 2
,如果我们走向右子树,那么 position -> positon x 2 + 1
。当我们在看同一层深度的位置值 L 和 R 的时候,宽度就是 R - L + 1
。
BFS
宽度优先搜索顺序遍历每个节点的过程中,我们记录节点的 position 信息,对于每一个深度,第一个遇到的节点是最左边的节点,最后一个到达的节点是最右边的节点。
class Solution:
def widthOfBinaryTree(self, root: TreeNode) -> int:
stack = [(root, 1, 1)] # root在第一层第一个位置
curr_level = 0 # 初始化层
left = 0 # 初始化left
ans = 0 # 初始化结果
while stack:
node, level, pos = stack.pop(0)
if node:
stack.append((node.left, level + 1, pos * 2)) # 左子树节点, 层数+1,位置为pos*2
stack.append((node.right, level + 1, pos * 2 + 1)) # 右子树节点,层数+1,位置为pos*2+1
if curr_level != level: # 进入新的一层,更新层数
curr_level = level
left = pos # 到达新层的第一个节点位置赋给left,后续节点的curr_levle一直等于level,不需要更新left;直到到达新的下一层,再更新层数
ans = max(pos - left + 1, ans) # 计算当前位置节点距离当前层最左侧的距离,更新结果
return ans
复杂度分析
时间复杂度: O(N),其中 N 是输入树的节点数目,我们遍历每个节点一遍。
空间复杂度: O(N),这是stack 的大小。
DFS
按照深度优先的顺序,我们记录每个节点的 position 。对于每一个深度,第一个到达的位置会被记录在 left[depth] 中。
然后对于每一个节点,它对应这一层的可能宽度是 pos - left[depth] + 1 。我们将每一层这些可能的宽度去一个最大值就是答案。
class Solution:
def widthOfBinaryTree(self, root: TreeNode) -> int:
self.ans = 0
self.left = {} # 记录每一层最先到达的节点位置
self.dfs(root)
return self.ans
def dfs(self, node, depth=0, pos=1):
if node:
self.left.setdefault(depth, pos) # depth不在就添加,在的话,就不更新,相当于下面两行
# if depth not in self.left:
# self.left[depth] = pos
self.ans = max(self.ans, pos - self.left[depth] + 1)
self.dfs(node.left, depth + 1, pos * 2)
self.dfs(node.right, depth + 1, pos * 2 + 1)
复杂度分析
时间复杂度: O(N) ,其中 N 是树中节点的数目,我们需要遍历每个节点。
空间复杂度: O(N) ,这部分空间是因为我们 DFS 递归过程中有 N 层的栈。
setdefault() 方法
Python 字典 setdefault() 方法和 get() 方法类似,返回指定键的值,如果键不在字典中,将会添加键并将值设置为一个指定值,默认为None。
get() 和 setdefault() 区别: setdefault() 返回的键如果不在字典中,会添加键(更新字典),而 get() 不会添加键。
语法
setdefault() 方法语法:
D.setdefault(key[,default=None])