如上图,我们只需要进行一次搜索,不妨使用 DFS(没有特殊理由,我一般都是 DFS),将节点存储到一个哈希表中,其中 key 为节点的 x 值,value 为横坐标为 x 的节点值列表(不妨用数组表示)。形如:
{1: [1,3,4]-1: [5]}
数据是瞎编的,不和题目例子有关联
经过上面的处理, 这个时候只需要对哈希表中的数据进行一次排序输出即可。
ok,如果这个你懂了,我们尝试加上面的两个限制加上去。
从上到下的顺序报告结点的值(Y 坐标递减)
如果两个结点位置相同,则首先报告的结点值较小。
关于第一个限制。其实我们可以再哈希表中再额外增加一层来解决。形如:
{1: { -2,[1,3,4] -3,[5] }, -1: { -3: [6] }}
这样我们除了对 x 排序,再对里层的 y 排序即可。
再来看第二个限制。其实看到上面的哈希表结构就比较清晰了,我们再对值排序即可。
总的来说,我们需要进行三次排序,分别是对 x 坐标,y 坐标 和 值。
那么时间复杂度是多少呢?我们来分析一下:
哈希表最外层的 key 总个数是最大是树的宽度。
哈希表第二层的 key 总个数是树的高度。
哈希表值的总长度是树的节点数。
也就是说哈希表的总容量和树的总的节点数是同阶的。因此空间复杂度为 $O(N)$, 排序的复杂度大致为 $NlogN$,其中 N 为树的节点总数。
代码
代码支持:Python,JS,CPP
Python Code:
classSolution(object):defverticalTraversal(self,root): seen = collections.defaultdict(lambda: collections.defaultdict(list))defdfs(root,x=0,y=0):ifnot root:return seen[x][y].append(root.val)dfs(root.left, x-1, y+1)dfs(root.right, x+1, y+1)dfs(root) ans = []# x 排序、for x insorted(seen): level = []# y 排序for y insorted(seen[x]):# 值排序 level +=sorted(v for v in seen[x][y]) ans.append(level)return ans
JS Code(by @suukii):
/** * Definition for a binary tree node. * function TreeNode(val) { * this.val = val; * this.left = this.right = null; * } *//** * @param{TreeNode} root * @return{number[][]} */varverticalTraversal=function (root) {if (!root) return [];// 坐标集合以 x 坐标分组constpos= {};// dfs 遍历节点并记录每个节点的坐标dfs(root,0,0);// 得到所有节点坐标后,先按 x 坐标升序排序let sorted =Object.keys(pos).sort((a, b) =>+a -+b).map((key) => pos[key]);// 再给 x 坐标相同的每组节点坐标分别排序 sorted =sorted.map((g) => {g.sort((a, b) => {// y 坐标相同的,按节点值升序排if (a[0] === b[0]) return a[1] - b[1];// 否则,按 y 坐标降序排elsereturn b[0] - a[0]; });// 把 y 坐标去掉,返回节点值returng.map((el) => el[1]); });return sorted;// *********************************functiondfs(root, x, y) {if (!root) return; x in pos || (pos[x] = []);// 保存坐标数据,格式是: [y, val] pos[x].push([y,root.val]);dfs(root.left, x -1, y -1);dfs(root.right, x +1, y -1); }};