题目: 给定二叉树,按垂序遍历返回其结点值。对位于 (X, Y) 的每个结点而言,其左右子结点分别位于 (X-1, Y-1) 和 (X+1, Y-1)。
把一条垂线从 X = -infinity 移动到 X = +infinity ,每当该垂线与结点接触时,我们按从上到下的顺序报告结点的值( Y 坐标递减)。如果两个结点位置相同,则首先报告的结点值较小。按 X 坐标顺序返回非空报告的列表。每个报告都有一个结点值列表。
来源: https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/
法一: 自己的代码
思路:利用层序遍历来实现,每一层弄一个小字典,如果出现同一个key下有两个值的情况,排序(必须是小字典排序,大字典排序是错的),最后再将小字典合并入大字典.
# Definition for a binary tree node. class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None from typing import List # 执行用时 :40 ms, 在所有 python3 提交中击败了91.14% 的用户 # 内存消耗 :12.7 MB, 在所有 python3 提交中击败了100.00%的用户 class Solution: def verticalTraversal(self, root: TreeNode) -> List[List[int]]: result = [] stack = [] # dict_1字典用于记录每一层的数据,dict记录合并后的 dict = {} dict_1 = {} if root is None: return [] # 利用层序遍历,上下位置可以确定,所以只记录节点的左右位置即可 stack.append((root,0)) stack_next = [] while stack: stack_next = stack stack = [] while stack_next: a,b = stack_next.pop(0) # 对于每一层的节点,如果这个key存在这务必排序(题目要求) if b in dict_1.keys(): dict_1[b] = sorted(dict_1[b] + [a.val]) else: dict_1[b] = [a.val] if a.left: stack.append((a.left,b-1)) if a.right: stack.append((a.right,b+1)) # 每遍历完一层后,将dict_1合并如dict for i in dict_1.keys(): if i in dict.keys(): dict[i] = dict[i] + dict_1[i] else: dict[i] = dict_1[i] # 为下一层存数据做准备 dict_1 = {} # 将字典化为list,生成结果 for i in sorted(dict): result.append(dict[i]) return result if __name__ == '__main__': duixiang = Solution() root = TreeNode(1) a = TreeNode(2) b = TreeNode(3) root.left = a root.right = b al = TreeNode(4) ar = TreeNode(10) a.left = al a.right = ar b.left = TreeNode(9) a = duixiang.verticalTraversal(root) print(a)
利用前序遍历迭代法是错的,因为这样无法保证顺序,下面用的层序法也是错误的的.写代码前一定要枚举个各种可能的情况,如果是写完了再考虑到这种情况很可能要大改代码.错误代码也可以在栈中加上层数修改,懒得写了.
class Solution:
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
result = []
stack = []
dict = {}
if root is None:
return []
stack.append((root,0))
while stack:
a,b = stack.pop(0)
if b in dict.keys():
dict[b].append(a.val)
else:
dict[b] = [a.val]
if a.left:
stack.append((a.left,b-1))
if a.right:
stack.append((a.right,b+1))
for i in sorted(dict):
result.append(dict[i])
return result
法二: 官方解法
利用defaultdict来实现,大大简化了代码,这种方法是先把每个节点都遍历一遍,记录下其二维坐标,最后再分组排序,与遍历方法无关.
# Definition for a binary tree node. class TreeNode: def __init__(self, x): self.val = x self.left = None self.right = None import collections class Solution(object): def verticalTraversal(self, root): # 这里实际上构建了一个二维坐标,用于下面存储数据 seen = collections.defaultdict(lambda: collections.defaultdict(list)) def dfs(node, x=0, y=0): # 如果节点不为空,则将节点的地址存储, if node: seen[x][y].append(node) # 这里实际上是前序遍历,但由于把坐标记录了,后续还要排序,所以与遍历方法无关 dfs(node.left, x-1, y+1) dfs(node.right, x+1, y+1) dfs(root) ans = [] # 这儿的seen的key一定要排序,因为输出的时候是从左往右输出 # 第一个坐标确定左右位置,第二个坐标确定层数位置. for x in sorted(seen): report = [] for y in sorted(seen[x]): # 题目规定同层的要排序,小在前大在后 report.extend(sorted(node.val for node in seen[x][y])) ans.append(report) return ans if __name__ == '__main__': duixiang = Solution() root = TreeNode(1) a = TreeNode(2) b = TreeNode(3) root.left = a root.right = b al = TreeNode(4) ar = TreeNode(10) a.left = al a.right = ar b.left = TreeNode(9) a = duixiang.verticalTraversal(root)