Open azl397985856 opened 2 years ago
这个题的重点在于排序,观察题目可知,坐标反映的是 (depth,order)
,我们需要对 order 升序,order 一样的(是一组)按 depth 升序,depth 一样的按 node.val
升序
// 坐标是 (depth,order)
var verticalTraversal = function (root) {
if (!root) return [];
let queue = [[root, 0, 0]];
// map缓存的是 order, [[node, depth],[node, depth]]
let map = new Map();
let min = Infinity;
let max = -Infinity;
let finalArr = [];
while (queue.length > 0) {
let first = queue.pop();
let node = first[0];
let order = first[2];
let depth = first[1];
min = Math.min(order, min);
max = Math.max(order, max);
if (map.has(order)) {
let arr = map.get(order);
arr.push([node, depth]);
map.set(order, arr);
} else {
map.set(order, [[node, depth]]);
}
if (node.left) {
queue.unshift([node.left, depth + 1, order - 1]);
}
if (node.right) {
queue.unshift([node.right, depth + 1, order + 1]);
}
}
for (let i = min; i <= max; i++) {
let arr = map.get(i);
arr.sort((a, b) => {
// 如果depth相同,就按照 node.val 升序排列
if (a[1] === b[1]) {
return a[0].val - b[0].val;
}
// 否则就按着 depth 升序排列
return a[1] - b[1];
});
// 我们最后要缓存的只是 node.val
arr = arr.map((elem) => elem[0].val);
finalArr.push(arr);
}
return finalArr;
};
https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/
给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。
对位于 (row, col) 的每个结点而言,其左右子结点分别位于 (row + 1, col - 1) 和 (row + 1, col + 1) 。树的根结点位于 (0, 0) 。
二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。
返回二叉树的 垂序遍历 序列。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[9],[3,15],[20],[7]]
解释:
列 -1 :只有结点 9 在此列中。
列 0 :只有结点 3 和 15 在此列中,按从上到下顺序。
列 1 :只有结点 20 在此列中。
列 2 :只有结点 7 在此列中。
示例 2:
输入:root = [1,2,3,4,5,6,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
列 -2 :只有结点 4 在此列中。
列 -1 :只有结点 2 在此列中。
列 0 :结点 1 、5 和 6 都在此列中。
1 在上面,所以它出现在前面。
5 和 6 位置都是 (2, 0) ,所以按值从小到大排序,5 在 6 的前面。
列 1 :只有结点 3 在此列中。
列 2 :只有结点 7 在此列中。
示例 3:
输入:root = [1,2,3,4,6,5,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
这个示例实际上与示例 2 完全相同,只是结点 5 和 6 在树中的位置发生了交换。
因为 5 和 6 的位置仍然相同,所以答案保持不变,仍然按值从小到大排序。
提示:
树中结点数目总数在范围 [1, 1000] 内
0 <= Node.val <= 1000
DFS + 三元组
JavaScript Code:
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var verticalTraversal = function(root) {
const nodeArr = [];
const getNodeArr = function dfs(root, i, j) {
if (!root) return;
nodeArr.push([i, j, root.val]);
dfs(root.left, i + 1, j - 1);
dfs(root.right, i + 1, j + 1);
};
getNodeArr(root, 0, 0);
nodeArr.sort((a, b) => {
if (a[1] !== b[1]) return a[1] - b[1];
if (a[0] !== b[0]) return a[0] - b[0];
return a[2] - b[2];
});
const resArr = [];
let lastCol = -1010; // -1000 <= col <= 1000
for (let i = 0; i < nodeArr.length; ++i) {
let curCol = nodeArr[i][1];
if (curCol !== lastCol) {
lastCol = curCol;
resArr.push([]);
}
resArr[resArr.length - 1].push(nodeArr[i][2]);
}
return resArr;
};
复杂度分析
var verticalTraversal = function(root) {
if(!root) return [];
let queue = [[root, 0, 0]];
let objMap = new Map();
let min = Infinity;
let max = -Infinity;
let finalArr = [];
while(queue.length > 0) {
let first = queue.pop();
let nodeObj = first[0];
let scaleLevel = first[1];
let depth = first[2];
min = Math.min(scaleLevel, min);
max = Math.max(scaleLevel, max);
if(objMap.has(scaleLevel)) {
let arr = objMap.get(scaleLevel);
arr.push([nodeObj, depth]);
objMap.set(scaleLevel, arr);
} else {
objMap.set(scaleLevel, [[nodeObj, depth]]);
}
if(nodeObj.left) {
queue.unshift([nodeObj.left, scaleLevel-1, depth+1]);
}
if(nodeObj.right) {
queue.unshift([nodeObj.right, scaleLevel+1, depth+1]);
}
};
for(let i=min; i<=max; i++) {
let arr = objMap.get(i);
arr.sort((a, b) => {
if(a[1] === b[1]) {
return a[0].val - b[0].val;
}
return a[1] - b[1];
})
arr = arr.map((elem) => elem[0].val);
finalArr.push(arr);
}
return finalArr;
};
深度优先遍历,用元组记录节点的数据,(行,列,节点值)。这也是排序的关键字
class Solution:
def __init__(self):
self.nodes = []
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
self.dfs(root, 0, 0)
self.nodes.sort()
ans, lastcol = list(), float("-inf")
for col, row, value in self.nodes:
if col != lastcol:
lastcol = col
ans.append(list())
ans[-1].append(value)
return ans
def dfs(self, node:TreeNode, row:int, col:int) -> None:
if not node:
return
self.nodes.append((col, row, node.val))
self.dfs(node.left, row + 1, col - 1)
self.dfs(node.right, row + 1, col + 1)
时间复杂度分析:O(NlogN),遍历O(N),主要在排序的复杂度O(NlogN) 空间复杂度分析:O(N)
三层的哈希表,分别按照x,y,val排序
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
seen = collections.defaultdict(lambda: collections.defaultdict(list))
def dfs(root, x=0, y=0):
if not 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 = []
for x in sorted(seen):
level = []
for y in sorted(seen[x]):
level += sorted(v for v in seen[x][y])
ans.append(level)
return ans
时间复杂度:O(nlogn) 空间复杂度:O(n)
思路
DFS, 先序遍历,记录每个节点的row和col,存储到map中,map中col为key值,value为对象数组[{row: row, val: root.val}]。
对map的key排序,遍历key获取map的值,将取出来的数组根据row和val的值排序(先比较row的大小,row相同再比较val),再将排序好的数组push到结果数组res中。
map: { 0:[ {row: row, val: root.val} ] }
代码 var verticalTraversal = function(root) { let map = new Map(); let keys = [], res = []; let preOrder = function(root, row, col) { if (!root) return; if (map.has(col)) map.get(col).push({row: row, val: root.val}); else { map.set(col, [{row: row, val: root.val}]); keys.push(col); } preOrder(root.left, row + 1, col - 1); preOrder(root.right, row + 1, col + 1); }; preOrder(root, 0, 0); keys.sort((a,b) => { return a - b; }); for (let i = 0; i < keys.length; i++) { let arr = map.get(keys[i]); arr.sort((a,b) => { if (a.row === b.row) return a.val - b.val; else return a.row - b.row; }); res.push(arr.map(val => {return val.val})); } return res; }; 复杂度分析 time: O(nlogn) space: O(n)
选一种遍历方式将树的节点值进行保存,同时还有行和列,然后对列进行排行
class Solution {
public:
vector<tuple<int,int,int>> node;
void dfs(TreeNode* root, int row, int col)
{
if(root==nullptr)
{
return;
}
node.emplace_back(col,row,root->val);
dfs(root->left,row+1,col-1);
dfs(root->right,row+1,col+1);
}
vector<vector<int>> verticalTraversal(TreeNode* root) {
dfs(root,0,0);
sort(node.begin(),node.end());//进行排序,按照列行值。
int last_col = INT_MIN;
vector<vector<int>> result;
for(const auto& [col,row,val] : node)
{
if(col != last_col)
{
last_col = col;
result.emplace_back();//只是创建下一个数组
}
result.back().emplace_back(val);
}
return result;
}
};
对树进行遍历并记录 值 x y 记录, 将记录之后的数值排序
时间复杂度:O(n log n) 空间复杂度:O(n)
class Solution {
Map<TreeNode, int[]> map = new HashMap<>(); // col, row, val
public List<List<Integer>> verticalTraversal(TreeNode root) {
map.put(root, new int[]{0, 0, root.val});
dfs(root);
List<int[]> list = new ArrayList<>(map.values());
Collections.sort(list, (a, b)->{
if (a[0] != b[0]) {
return a[0] - b[0];
}
if (a[1] != b[1]) {
return a[1] - b[1];
}
return a[2] - b[2];
});
int n = list.size();
List<List<Integer>> ans = new ArrayList<>();
for (int i = 0; i < n; ) {
int j = i;
List<Integer> tmp = new ArrayList<>();
while (j < n && list.get(j)[0] == list.get(i)[0]) {
tmp.add(list.get(j++)[2]);
}
ans.add(tmp);
i = j;
}
return ans;
}
void dfs(TreeNode root) {
if (root == null) return ;
int[] info = map.get(root);
int col = info[0], row = info[1], val = info[2];
if (root.left != null) {
map.put(root.left, new int[]{col - 1, row + 1, root.left.val});
dfs(root.left);
}
if (root.right != null) {
map.put(root.right, new int[]{col + 1, row + 1, root.right.val});
dfs(root.right);
}
}
}
使用DFS遍历,用node结构体存储x,y,val。
class Solution {
public:
struct node{
int val;
int x;
int y;
node(int v,int X,int Y):val(v),x(X),y(Y){};
};
static bool cmp(node a, node b){
if (a.x^b.x)
return a.x<b.x;
if (a.y^b.y)
return a.y<b.y;
return a.val<b.val;
}
vector<node> a;
int minx=1000,maxx=-1000;
vector<vector<int>> verticalTraversal(TreeNode* root) {
dfs(root, 0, 0);
sort(a.begin(),a.end(),cmp);
vector<vector<int>>ans(maxx-minx+1);
for (auto i : a){
ans[i.x - minx].push_back(i.val);
}
return ans;
}
void dfs(TreeNode* root, int x, int y){
if (root == nullptr)
return;
if (x < minx)
minx = x;
if (x > maxx)
maxx = x;
a.push_back(node(root->val,x,y));
dfs(root->left, x-1, y+1);
dfs(root->right, x+1, y+1);
}
};
dfs 从根节点开始,对整棵树进行一次遍历,并在遍历过程中使用数组记录信息
class Solution:
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
nodes = list()
def dfs(node: TreeNode, row: int, col: int) -> None:
if not node:
return
nodes.append((col, row, node.val))
dfs(node.left, row + 1, col - 1)
dfs(node.right, row + 1, col + 1)
dfs(root, 0, 0)
nodes.sort()
ans, lastcol = list(), float("-inf")
for col, row, value in nodes:
if col != lastcol:
lastcol = col
ans.append(list())
ans[-1].append(value)
return ans
时间:O(nlogn) 空间:O(n)
4月18日
【day18】
难度 困难
给你二叉树的根结点 root
,请你设计算法计算二叉树的 垂序遍历 序列。
对位于 (row, col)
的每个结点而言,其左右子结点分别位于 (row + 1, col - 1)
和 (row + 1, col + 1)
。树的根结点位于 (0, 0)
。
二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。
返回二叉树的 垂序遍历 序列。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[9],[3,15],[20],[7]]
解释:
列 -1 :只有结点 9 在此列中。
列 0 :只有结点 3 和 15 在此列中,按从上到下顺序。
列 1 :只有结点 20 在此列中。
列 2 :只有结点 7 在此列中。
首先遍历整个树,将结点信息保存下来(col,row,val)
,按照规则进行排序;排序的规则是:首先按列从小到大,再按行从小到大,最后同行同列按照val从小到大,使用Collections.sort(list,compare)
的自定义排序,这个如果不会,先学一下。最后按照排好的顺序,『按列』构建出结果list。
class Solution {
List<int[]> list = new ArrayList();
public List<List<Integer>> verticalTraversal(TreeNode root) {
dfs(root,0,0);
Collections.sort(list, new Comparator<int[]>() {
public int compare(int[] o1, int[] o2) {
if(o1[0] != o2[0])
return o1[0]-o2[0];
if(o1[1] != o2[1])
return o1[1]-o2[1];
return o1[2]-o2[2];
}
});
List<List<Integer>> res = new ArrayList<List<Integer>>();
int last = Integer.MIN_VALUE;
int size = 0;
for(int[] arr : list){
int col = arr[0];
int row = arr[1];
int value = arr[2];
if(col != last){
last = col;
res.add(new ArrayList<Integer>());
size++;
}
res.get(size-1).add(value);
}
return res;
}
void dfs(TreeNode root,int row,int col){
if(root == null){
return ;
}
list.add(new int[]{col,row,root.val});
dfs(root.left,++row,--col);
row--;
col++;
dfs(root.right,++row,++col);
row--;
col--;
}
}
BFS
javaScript
/**
* @param {TreeNode} root
* @return {number[][]}
*/
var verticalTraversal = function(root) {
if(!root) return root
const result = []
const obj = new Map();
// [node, rowVal, colVal]
const queue = [[root,0, 0]]
while(queue.length){
const [node, row, col] = queue.shift()
obj.set(col, (obj.get(col) || []).concat([[node.val, row]]))
node.left && queue.push([node.left, row + 1, col - 1 ])
node.right && queue.push([node.right, row + 1 , col + 1 ])
}
// sort
let sortedKeys = [...obj.keys()].sort((a,b) => a - b)
for(const key of sortedKeys){
let temp = obj.get(key)
temp = temp.sort((a,b) => {
if(a[1] != b[1]){
return a[1] - b[1]
}
return a[0] - b[0]
})
result.push(temp.map((item) => item[0]))
}
return result;
};
将列值相同的放入同一个List中
class Solution {
public List<List<Integer>> verticalTraversal(TreeNode root) {
Queue<int[]> queue = new PriorityQueue<>((a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
}
if (a[1] != b[1]) {
return a[1] - b[1];
}
return a[2] - b[2];
});
dfs(0, 0, root, queue);
List<List<Integer>> res = new LinkedList<>();
while (!queue.isEmpty()) {
}
}
void dfs(int row, int col, TreeNode root, Queue<int[]> queue) {
if (root == null) {
return;
}
queue.offer(new int[]{row, col, root.val});
dfs(row + 1, col - 1, root.left, queue);
dfs(row + 1, col + 1, root.right, queue);
}
}
用一个vector保存坐标与值。
struct ValNode {
int x;
int y;
int val;
};
DFS遍历,并将坐标与值写入
按 y x val排序
打印
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
// DFS 遍历所有节点,并且把节点坐标放到暂存区中
void DFS(TreeNode* root, int x, int y) {
if (root == nullptr) {
return;
}
ValNode val_node{.x = x, .y=y, .val=root->val};
dp.emplace_back(val_node);
DFS(root->left, x+1, y-1);
DFS(root->right, x+1, y+1);
}
vector<vector<int>> verticalTraversal(TreeNode* root) {
DFS(root, 0, 0);
// 排序dp 按照 y x val 排序
std::sort(dp.begin(), dp.end(), [](const ValNode& a, const ValNode&b){
if (a.y < b.y) {
return true;
} else if (a.y > b.y) {
return false;
} else {
if (a.x < b.x) {
return true;
} else if (a.x > b.x) {
return false;
} else {
return a.val <= b.val;
}
}
});
// 打印
vector<vector<int>> ret_vec;
int last_y = -10001;
vector<int> tmp_dp;
for (const auto& node_val : dp) {
if (node_val.y != last_y && !tmp_dp.empty()) {
ret_vec.emplace_back(tmp_dp);
tmp_dp.clear();
}
tmp_dp.emplace_back(node_val.val);
last_y = node_val.y;
}
if (!tmp_dp.empty()) {
ret_vec.emplace_back(tmp_dp);
}
return ret_vec;
}
private:
struct ValNode {
int x;
int y;
int val;
};
vector<ValNode> dp;
};
时间: O(nLOG(n));
空间: O(N)
将列值相同的放入同一个List中
class Solution {
public List<List<Integer>> verticalTraversal(TreeNode root) {
Queue<int[]> queue = new PriorityQueue<>((a, b) -> {
if (a[0] != b[0]) {
return a[0] - b[0];
}
if (a[1] != b[1]) {
return a[1] - b[1];
}
return a[2] - b[2];
});
dfs(0, 0, root, queue);
List<List<Integer>> res = new LinkedList<>();
while (!queue.isEmpty()) {
}
}
void dfs(int row, int col, TreeNode root, Queue<int[]> queue) {
if (root == null) {
return;
}
queue.offer(new int[]{row, col, root.val});
dfs(row + 1, col - 1, root.left, queue);
dfs(row + 1, col + 1, root.right, queue);
}
}
DFS + 优先级队列
public List<List
public void dfs(TreeNode node, int row, int col, List<int[]> nodes) {
if (node == null) {
return;
}
nodes.add(new int[]{col, row, node.val});
dfs(node.left, row + 1, col - 1, nodes);
dfs(node.right, row + 1, col + 1, nodes);
}
BFS 需要使用一个map来存储不同y值的节点 我们每次遍历的节点的y值是相同的,那么我们可以将此次遍历的节点都存储到一个临时的map中,当遍历结束后,我们可以遍历这个临时的map,根据不同的y值去从到大排序。 最后将排好序的节点再加入到我们的第一个map即可。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
struct Node {
int x { 0 };
int y { 0 };
TreeNode *root { nullptr };
Node() {}
Node(int a, int b, TreeNode *c) : x(a), y(b), root(c) {}
};
vector <vector <int>> ans;
map <int, vector<int>> ss;
vector<vector<int>> verticalTraversal(TreeNode* root) {
if (root == nullptr) {
return ans;
}
queue <Node> q;
q.push({0, 0, root});
while (!q.empty()) {
int n = q.size();
map <int, vector<int>> tmp; // 临时的 map
for(int i = 0; i < n; i++) {
auto k = q.front();
q.pop();
tmp[k.y].push_back(k.root->val);
if(k.root->left) q.push({k.x + 1, k.y - 1, k.root->left});
if(k.root->right) q.push({k.x + 1, k.y + 1, k.root->right});
}
for (auto &[x, y] : tmp) { // 遍历
sort(y.begin(), y.end()); // 排序
for (auto &c : y) {
ss[x].push_back(c); // 将节点加入第一个 map(ss) 中
}
}
tmp.clear();
}
for(auto &[x, y] : ss) {
ans.push_back(y);
}
return ans;
}
};
复杂度分析
class Solution:
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
hashmap = defaultdict(list)
def dfs(node, x, y):
if not node:
return
hashmap[y].append((x,node.val))
dfs(node.left, x+1, y-1)
dfs(node.right,x+1, y+1)
dfs(root, 0, 0)
return [list(zip(*sorted(hashmap[i])))[1] for i in sorted(hashmap.keys())]
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def verticalTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
res = [];
queue = collections.deque();
queue.append((root,0,0));
while queue:
curr, x, y = queue.popleft();
if curr:
res.append([curr.val, x,y]);
queue.append((curr.left, x+1,y-1));
queue.append((curr.right,x+1,y+1));
ans = [];
res = sorted(res, key = lambda x : (x[2], x[1], x[0]));
print(res)
ans = OrderedDict();
for value,row, column in res:
if column in ans:
ans[column].append(value);
else:
ans[column] = [value];
return ans.values();
思路:层次遍历,先处理一层的节点,然后将这一层的节点排序后,加入总的结果中,用字典来存储结果,字典的key是列的值。
复杂度分析: 时间复杂度: O(N+Mlog M+QlogQ) , 主要是层次遍历的复杂度O(N), 以及排序的复杂度O(MlogM),其中M是最后的column的个数,Q是最坏情况下同一层的节点都在同一列,大致为O(NlogN). 空间复杂度:O(N), 哈希表的大小与节点个数同阶
代码如下:
class Solution:
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
re = {}
node_queue = [root]
col_queue = [0]
while node_queue:
length = len(node_queue)
layer_re = {}
for _ in range(length):
node = node_queue.pop(0)
col = col_queue.pop(0)
if col not in layer_re.keys():
layer_re[col] = [node.val]
else:
layer_re[col].append(node.val)
if node.left:
node_queue.append(node.left)
col_queue.append(col-1)
if node.right:
node_queue.append(node.right)
col_queue.append(col+1)
for i in layer_re.keys():
layer_re[i].sort()
if i not in re.keys():
re[i] = layer_re[i]
else:
re[i].extend(layer_re[i])
Col = list(re.keys())
Col.sort()
result = []
for col in Col:
result.append(re[col])
return result
中序遍历,给每个节点产生一个(row, col)坐标,然后收集坐标进行排序即可。 但是排序那段代码看上去比较的啰嗦,后面看看其它答案优化一下吧
func verticalTraversal(root *TreeNode) [][]int {
// map[column]map[line][]int
var nodes = make(map[int]map[int][]int, 0)
var travel func(node *TreeNode, row, col int)
travel = func(node *TreeNode, row, col int) {
if node == nil {
return
}
if _, ok := nodes[col]; !ok {
nodes[col] = map[int][]int{row: {node.Val}}
} else if _, ok = nodes[col][row]; !ok {
nodes[col][row] = []int{node.Val}
} else {
nodes[col][row] = append(nodes[col][row], node.Val)
}
travel(node.Left, row + 1, col - 1)
travel(node.Right, row + 1, col + 1)
}
travel(root, 0, 0)
// fmt.Printf("nodes: %+v\n", nodes)
ret := make([][]int, 0, len(nodes))
// 列排序
colKeys := make([]int, 0, len(nodes))
for k := range nodes {
colKeys = append(colKeys, k)
}
sort.Ints(colKeys)
// fmt.Printf("colKeys: %+v\n", colKeys)
for _, k := range colKeys {
// 行排序
rowKeys := make([]int, 0, len(nodes[k]))
for i := range nodes[k] {
rowKeys = append(rowKeys, i)
}
sort.Ints(rowKeys)
// fmt.Printf("colKey: %d, rowKeys: %+v\n", k, rowKeys)
colRet := make([]int, 0)
for _, r := range rowKeys {
rowData := nodes[k][r]
sort.Ints(rowData)
colRet = append(colRet, rowData...)
}
ret = append(ret, colRet)
}
return ret
}
复杂度分析
class Solution {
public:
void helper(TreeNode* p, int x, int y){
if(!p) return;
map[x].insert(y * 10000 + p->val);
helper(p->left, x-1, y+1);
helper(p->right, x+1, y+1);
return;
}
vector<vector<int>> verticalTraversal(TreeNode* root) {
helper(root, 0, 0);
vector<vector<int>> result;
for(auto x:map){
vector<int> curr;
for(auto y:x.second) curr.push_back(y % 10000);
result.push_back(curr);
}
return result;
}
private:
map<int,set<int>> map;
};
4.18
思路:
记录每一个列出现的所有数字(带行数),按列排序,按行排序,按值排序即可。
代码:
class Solution:
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
hashmap = defaultdict(list)
def dfs(node, x, y):
if not node:
return
hashmap[y].append((x,node.val))
dfs(node.left, x+1, y-1)
dfs(node.right,x+1, y+1)
dfs(root, 0, 0)
return [list(zip(*sorted(hashmap[i])))[1] for i in sorted(hashmap.keys())]
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
/*
# Plan1:
preorder
- track depth
- vertical distance (go left: - 1, right + 1)
nested map:
- key sorted by vertical distances (its values sorted by treenode val)
TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>
no need to specifically track minVertical, maxVertical if we use treemap
Time:
touch each node once during dfs, O(n)
offer each node to pq and poll each node from pq
O(nlogn)
Space:
map: O(n), n = number of nodes
dfs: O(height)
# Plan2: BFS + hashmap x->pairs
Time:
- bfs, touch on each node once
- Collections.sort on each list of same x,
assume: i number of possible x's, on average j nodes for each
i * jlog(j) = n log j, n = number of nodes
- add to list O(n)
Space: queue O(widest) = O[(n+1)/2] = O(n)
hashmap: store number of pairs = number of nodes, O(n)
->assume: i number of possible x's, on average j nodes for each, either way i * j = n
*/
class Solution {
public List<List<Integer>> verticalTraversal1(TreeNode root) {
TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>> VThenDepthMap = new TreeMap<>();
dfs(root, 0, 0, VThenDepthMap);
List<List<Integer>> traversal = new ArrayList<>();
// when we traverse, vertical is sorted (vertically, go from left to right)
for (TreeMap<Integer, PriorityQueue<Integer>> sortedDtosortedVals : VThenDepthMap.values()) {
traversal.add(new ArrayList<>());
// start from min vertical distance, go from top to bottom, if same depth (also same vertical), smaller comes first
for (PriorityQueue<Integer> sortedValsOfSameD : sortedDtosortedVals.values()) {
while (!sortedValsOfSameD.isEmpty()) {
traversal.get(traversal.size() - 1).add(sortedValsOfSameD.poll()); // poll() once for each node, O(nlogn)
}
}
}
return traversal;
}
// x: vertical, y : level
// time: for each node val, need to be inserted to the right priorityqueue O(nlogn)
// touch each node once O(n)
// intotal O(nlogn)
private void dfs(TreeNode cur, int x, int y, TreeMap<Integer, TreeMap<Integer, PriorityQueue<Integer>>> VThenDepthMap) {
if (cur == null) {
return;
}
if (!VThenDepthMap.containsKey(x)) {
VThenDepthMap.put(x, new TreeMap<> ());
}
if (!VThenDepthMap.get(x).containsKey(y)) {
VThenDepthMap.get(x).put(y, new PriorityQueue<>());
}
VThenDepthMap.get(x).get(y).offer(cur.val);
dfs(cur.left, x - 1, y + 1, VThenDepthMap);
dfs(cur.right, x + 1, y + 1, VThenDepthMap);
}
// Method 2: level-order + hashmap
class Pair {
TreeNode node;
int x;
int y;
Pair(TreeNode node, int x, int y) {
this.node = node;
this.x = x;
this.y = y;
}
}
public List<List<Integer>> verticalTraversal(TreeNode root) {
List<List<Integer>> traversal = new ArrayList<>();
// vertical distance -> list of pairs
Map<Integer, List<Pair>> xToPairsMap = new HashMap<>();
// BFS
Queue<Pair> queue = new LinkedList<>();
queue.offer(new Pair(root, 0, 0));
int minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
// BFS: O(n) time
while (!queue.isEmpty()) {
Pair cur = queue.poll();
if (cur.node == null) System.out.println(queue.size());
minX = Math.min(minX, cur.x);
maxX = Math.max(maxX, cur.x);
if (!xToPairsMap.containsKey(cur.x)) {
xToPairsMap.put(cur.x, new ArrayList<>());
}
xToPairsMap.get(cur.x).add(cur);
if (cur.node.left != null) {
queue.offer(new Pair(cur.node.left, cur.x - 1, cur.y + 1));
}
if (cur.node.right != null) {
queue.offer(new Pair(cur.node.right, cur.x + 1, cur.y + 1));
}
}
// sort
for (int v = minX; v <= maxX; v++) {
List<Pair> sameXPairs = xToPairsMap.get(v);
// sort by y (depth) first and then value
// if depth/y is the same, smaller value comes first
Collections.sort(sameXPairs, new Comparator<Pair>() {
public int compare(Pair a, Pair b) {
if (a.y == b.y) {
return a.node.val - b.node.val;
}
return 0; // bfs puts pairs of smaller depth first
}
});
List<Integer> sameX = new ArrayList<>();
for (Pair sameXPair : sameXPairs) {
sameX.add(sameXPair.node.val);
}
traversal.add(sameX);
}
return traversal;
}
}
自定义排序
java
public List<List<Integer>> verticalTraversal(TreeNode root) {
ArrayList<int[]> list = new ArrayList<>();
DFS(root,0,0,list);
Collections.sort(list, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[0]!=o2[0]){
return o1[0]-o2[0];
}else {
if (o1[1]!=o2[1]){
return o1[1]-o2[1];
}else {
return o1[2]-o2[2];
}
}
}
});
List<List<Integer>> ans = new ArrayList<>();
int size=0;
int left=Integer.MIN_VALUE;
for (int[] t:list){
if (t[0]!=left){
left=t[0];
ans.add(new ArrayList<>());
size++;
}
ans.get(size-1).add(t[2]);
}
return ans;
}
private void DFS(TreeNode root, int row, int col, ArrayList<int[]> list) {
if (root==null)return;
list.add(new int[]{col,row,root.val});
DFS(root.left,row+1,col-1,list);
DFS(root.right,row+1,col+1,list);
}
遍历树,存储值,row, col,接着对树节点的列表排序,最后按要求生成新列表。
def verticalTraversal(self, root) :
nodes = list()
def dfs(node: TreeNode, row: int, col: int) -> None:
if not node:
return
nodes.append((col, row, node.val))
dfs(node.left, row + 1, col - 1)
dfs(node.right, row + 1, col + 1)
dfs(root, 0, 0)
nodes.sort()
ans, lastcol = list(), float("-inf")
for col, row, value in nodes:
if col != lastcol:
lastcol = col
ans.append(list())
ans[-1].append(value)
return ans
时间 o(n log n) 首先遍历花费o(n), 排序花费o(nlogn),最后遍历节点列表花费o(n) 空间 o(n)
DFS + 排序
class Solution {
Map<Integer, Map<Integer, List<Integer>>> hashmap;
public List<List<Integer>> verticalTraversal(TreeNode root) {
hashmap = new HashMap<>();
dfs(root, 0, 0);
List<List<Integer>> res = new ArrayList<>();
List<Integer> tmp = new ArrayList<>();
List<Integer> js = new ArrayList(hashmap.keySet());
Collections.sort(js);
for(Integer j : js){
tmp = new ArrayList<>();
Map<Integer, List<Integer>> map = hashmap.get(j);
List<Integer> is = new ArrayList(map.keySet());
Collections.sort(is);
for(Integer i : is){
List<Integer> values = map.get(i);
Collections.sort(values);
tmp.addAll(values);
}
res.add(tmp);
}
return res;
}
private void dfs(TreeNode node, int j, int i){
if(node == null){
return;
}
if(!hashmap.containsKey(j)){
hashmap.put(j, new HashMap<>());
}
if(!hashmap.get(j).containsKey(i)){
hashmap.get(j).put(i, new ArrayList<>());
}
hashmap.get(j).get(i).add(node.val);
dfs(node.left, j - 1, i + 1);
dfs(node.right, j + 1, i + 1);
}
}
时间:O(NlogN)
空间:O(N)
先dfs遍历存储坐标数组,然后按照题目要求进行输出
var verticalTraversal = function(root) {
if (!root) return [];
let treenodeArr=[];
let dfs=function (root,x,y){
if (!root) return;
treenodeArr.push([x,y,root.val]);
dfs(root.left,x-1,y+1)
dfs(root.right,x+1,y+1);
};
dfs(root,0,0);
treenodeArr=treenodeArr.sort((a,b)=>{
if (a[0]!==b[0]) return a[0]-b[0];
else if (a[1]!==b[1]) return a[1]-b[1];
else return a[2]-b[2];
})
let curValOfX = treenodeArr[0][0];
let res = [[treenodeArr[0][2]]];
for (let i = 1; i < treenodeArr.length; i++) {
let location = treenodeArr[i];
let x = location[0];
if (x === curValOfX) {
let last = res[res.length - 1];
last.push(location[2]);
} else {
res.push([location[2]]);
}
}
return res;
};
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def verticalTraversal(self, root: Optional[TreeNode]) -> List[List[int]]:
"""
Ideas:
{
2: [4],
1: [2],
0: [5, 1, 6}
}
->
{
2: {2: [4]},
1: {1: [2]},
0: {0:[1], 2:[5, 6]}
}
save in dict + dict + list
sort x, sort y, sort value
TC: O(n) + O(nlogn) = O(nlogn)
SC: O(n)
"""
seen = collections.defaultdict(lambda: collections.defaultdict(list))
def dfs(root, x, y):
if not root: return
dfs(root.left,x - 1, y + 1)
seen[x][y].append(root.val)
dfs(root.right, x + 1, y + 1)
dfs(root, 0, 0)
ans = []
for x in sorted(seen):
level = []
for y in sorted(seen[x]):
level += sorted(seen[x][y])
ans.append(level)
return ans
思路:这题已经给出提示了,所有的二叉树节点都可以用坐标表示。那么我们只需要DFS遍历一遍给所有节点标记对应的坐标并且加入到一个集合里,然后按照要求的排序方式输出就好啦 代码:代码参考官方题解
struct node
{
int val;
int x;
int y;
node(int i_val, int i_x,int i_y):val(i_val),x(i_x),y(i_y){};
};
static bool cmp(node a,node b)
{
if(a.x^b.x)
return a.x<b.x;
if(a.y^b.y)
return a.y<b.y;
return a.val<b.val;
}
vector<node> nodeArr;
int minX=INT_MAX;
int maxX=INT_MIN;
vector<vector<int>> verticalTraversal(TreeNode* root)
{
dfs(root,0,0);
sort(nodeArr.begin(),nodeArr.end(),cmp);
vector<vector<int>> res(maxX-minX+1);
for(node son:nodeArr)
{
res[son.x-minX].push_back(son.val);
}
return res;
}
void dfs(TreeNode* root,int x,int y)
{
if(root==nullptr) return;
if(x<minX)
minX=x;
if(x>maxX)
maxX=x;
nodeArr.push_back(node(root->val,x,y));
dfs(root->left,x-1,y+1);
dfs(root->right,x+1,y+1);
}
复杂度: 时间复杂度:O(nlogn) 空间复杂度:O(n)
代码:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def verticalTraversal(self, root: TreeNode) -> List[List[int]]:
q = [root]
min = 0
max = 0
if not root:
return None
lo = [[[root.val, 0, 0]]]
level = 0
while q:
child=[]
lo.append([])
for i in range(len(q)):
if q[i].left:
child.append(q[i].left)
lo[-1].append([q[i].left.val, lo[level][i][1] + 1, lo[level][i][2] - 1])
if q[i].right:
child.append(q[i].right)
lo[-1].append([q[i].right.val, lo[level][i][1] + 1, lo[level][i][2] + 1])
q = child
level += 1
if not child:
lo.pop()
new = []
for i in lo:
for j in i:
new.append(j)
new = sorted(new,key = lambda x: x[2])
col = []
tar = []
row = {}
temp = []
for i in new:
if i[2] not in col:
tar.append([])
col.append(i[2])
row.clear()
if i[1]not in row:
tar[-1].append(i[0])
row[i[1]] = 1
else:
while row[i[1]]>0:
temp.append(tar[-1].pop())
row[i[1]] -= 1
temp.append(i[0])
temp.sort()
row[i[1]] = len(temp)
tar[-1].extend(temp)
temp = []
return tar
dfs遍历树,使其形成{col: {row :[val1, val2...]}}的结构,然后分别对col、row以及[val1,val2...]进行排序即可
var verticalTraversal = function(root) {
let nodes = {};
dfs(root, 0, 0, nodes);
let res = [];
for(let col of Object.keys(nodes).sort((a, b) => a - b)){
let temp = [];
for(let row of Object.keys(nodes[col]).sort((a, b) => a - b)){
if(nodes[col][row].length == 1){
temp = temp.concat(nodes[col][row]);
}
else{
temp = temp.concat(nodes[col][row].sort((a, b) => a - b));
}
}
res.push(temp);
}
return res;
};
var dfs = function(node, row, col, nodes){
if(node === null) return;
if(col in nodes){
if(row in nodes[col]){
nodes[col][row].push(node.val);
}
else{
let temp = nodes[col];
temp[row] = [node.val];
nodes[col] = temp;
}
}
else{
let temp = {};
temp[row] = [node.val];
nodes[col] = temp;
}
dfs(node.left, row + 1, col - 1, nodes);
dfs(node.right, row + 1, col + 1, nodes);
}
BFS: use a priorityQueue instead of queue to make each level sorted by row than by node.val Put verticalNode into TreeMap to sort col during BFS Data structure: Use TreeMap sort col; Use PriorityQueue sort row then sort node.val map holds the result
class Solution {
public List<List<Integer>> verticalTraversal(TreeNode root) {
// sort by row then node.val
PriorityQueue<VerticalNode> q = new PriorityQueue<>((a, b) -> {
if (a.row == b.row) {
return a.node.val - b.node.val;
}
else {
return a.row - b.row;
}
});
Map<Integer, List<Integer>>map = new TreeMap<>(); // key is col, sort by col
q.offer(new VerticalNode(root, 0, 0));
while (!q.isEmpty()) {
VerticalNode curr = q.poll();
List<Integer> list = map.getOrDefault(curr.col, new ArrayList<>());
list.add(curr.node.val);
map.put(curr.col, list);
if (curr.node.left != null) {
q.offer(new VerticalNode(curr.node.left, curr.col-1, curr.row+1));
}
if (curr.node.right != null) {
q.offer(new VerticalNode(curr.node.right, curr.col+1, curr.row+1));
}
}
List<List<Integer>> res = new ArrayList<>();
for (List<Integer> values : map.values()) {
res.add(values);
}
return res;
}
class VerticalNode {
TreeNode node;
int col;
int row;
public VerticalNode(TreeNode n, int c, int r) {
node = n;
col = c;
row = r;
}
}
}
Time: O(nlogn) n times heapify Space: O(n)
用map记录每个坐标节点list的值,最后加进来的时候要把同坐标的list排序
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def verticalTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
self.seen = collections.defaultdict(lambda: collections.defaultdict(list))
self.dfs(root, 0, 0)
res = []
for col in sorted(self.seen):
level = []
for row in sorted(self.seen[col]):
level += list(v for v in sorted(self.seen[col][row]))
res.append(level[:])
return res
def dfs(self, root, row, col):
if not root:
return
self.seen[col][row].append(root.val)
self.dfs(root.left, row + 1, col - 1)
self.dfs(root.right, row + 1, col + 1)
time O(NlogN) space O(N)
987. 二叉树的垂序遍历
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree
前置知识
题目描述
对位于 (X, Y) 的每个结点而言,其左右子结点分别位于 (X-1, Y-1) 和 (X+1, Y-1)。
把一条垂线从 X = -infinity 移动到 X = +infinity ,每当该垂线与结点接触时,我们按从上到下的顺序报告结点的值(Y 坐标递减)。
如果两个结点位置相同,则首先报告的结点值较小。
按 X 坐标顺序返回非空报告的列表。每个报告都有一个结点值列表。
示例 1:
输入:[3,9,20,null,null,15,7] 输出:[[9],[3,15],[20],[7]] 解释: 在不丧失其普遍性的情况下,我们可以假设根结点位于 (0, 0): 然后,值为 9 的结点出现在 (-1, -1); 值为 3 和 15 的两个结点分别出现在 (0, 0) 和 (0, -2); 值为 20 的结点出现在 (1, -1); 值为 7 的结点出现在 (2, -2)。 示例 2:
输入:[1,2,3,4,5,6,7] 输出:[[4],[2],[1,5,6],[3],[7]] 解释: 根据给定的方案,值为 5 和 6 的两个结点出现在同一位置。 然而,在报告 "[1,5,6]" 中,结点值 5 排在前面,因为 5 小于 6。
提示:
树的结点数介于 1 和 1000 之间。 每个结点值介于 0 和 1000 之间。