作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址:https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/

题目描述

Given a binary tree, return the vertical order traversal of its nodes values.

For each node at position (X, Y), its left and right children respectively will be at positions (X-1, Y-1) and (X+1, Y-1).

Running a vertical line from X = -infinity to X = +infinity, whenever the vertical line touches some nodes, we report the values of the nodes in order from top to bottom (decreasing Y coordinates).

If two nodes have the same position, then the value of the node that is reported first is the value that is smaller.

Return an list of non-empty reports in order of X coordinate. Every report will have a list of values of nodes.

Example 1:

Input: [3,9,20,null,null,15,7]
Output: [[9],[3,15],[20],[7]]
Explanation:
Without loss of generality, we can assume the root node is at position (0, 0):
Then, the node with value 9 occurs at position (-1, -1);
The nodes with values 3 and 15 occur at positions (0, 0) and (0, -2);
The node with value 20 occurs at position (1, -1);
The node with value 7 occurs at position (2, -2).

Example 2:

Input: [1,2,3,4,5,6,7]
Output: [[4],[2],[1,5,6],[3],[7]]
Explanation:
The node with value 5 and the node with value 6 have the same position according to the given scheme.
However, in the report "[1,5,6]", the node value of 5 comes first since 5 is smaller than 6.

Note:

  1. The tree will have between 1 and 1000 nodes.
  2. Each node’s value will be between 0 and 1000.

题目大意

一个二叉树从左到右竖着看,每列的结果放到一起,那么结果是什么样的。

规定:一个节点水平方向的位置是X,竖直方向的高度是Y,其坐标是(X, Y)。那么其左右孩子的坐标分别是(X-1, Y-1) and (X+1, Y-1).

即要求把相同X的节点位置放在一起,并且要求结果中节点的存放是从上到下的。如果两个节点的坐标相同,那么value小的节点排列在前面。

解题方法

DFS

最直白的方法就是把每个节点的位置给求出来,然后构建出题目要求的排列方式。为了方便,我们在求的过程中就把相同X值的放到一起,同时保存Y坐标和值。

所以定义了一个Map,这个Map的结构是map<int, vector<pair<int, int>>>,保存的是x ==> (-y, value)的映射。所以在进行DFS的过程中,我们会给每个坐标都记录下其坐标(X,Y),然后我们根据其坐标把相同X的都放到一起。为什么使用-y呢?这是因为题目中告诉我们节点的Y坐标更小,而题目要求的Y排序是顺序是从上到下的。如果设置根节点层的Y坐标是0的话,那么下面各层的真实Y值应该是-1,-2,-3……,我们的sort函数默认是递增排序的,所以为了sort方便,放到vector中的是-y。

在求出相同X的所有(-y, value)对之后,我们进行了排序使得Y值是严格递增的,当Y值相同时按照value值进行排序。然后把排序好了的节点的value值都取出来放到结果里即可。

一个不引起注意的点是,nodeMap一定要使用map数据结构,而不是unordered_map。因为map会保证有序的,也就是说对nodeMap遍历的时候,X是已经排序好了。而unordered_map是无序结构,遍历不会保证X是有序,增加了麻烦。

另外一个C++的知识点是当使用 for (auto nm : nodeMap)的时候,nm不是一个指针,而是一个复制了的对象,所以不要使用nm->second,而应该使用nm.second.

时间复杂度是O(N + N*(N*log(N) + N))。第一个N是DFS要把每个节点进行遍历一次;for循环有层N,循环里面有层排序是NlogN,遍历是N)。

空间复杂度是O(N)。

C++代码如下:

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> verticalTraversal(TreeNode* root) {
nodeMap.clear();
dfs(root, 0, 0);
vector<vector<int>> res;
for (auto nm : nodeMap) {
sort(nm.second.begin(), nm.second.end());
vector<int> cols;
for (auto p : nm.second)
cols.push_back(p.second);
res.push_back(cols);
}
return res;
}
private:
map<int, vector<pair<int, int>>> nodeMap; // x ==> (-y, value)
void dfs(TreeNode* root, int x, int y) {
if (!root) return;
nodeMap[x].emplace_back(-y, root->val);
dfs(root->left, x - 1, y - 1);
dfs(root->right, x + 1, y - 1);
}
};

下面的python代码没有使用字典,而是使用了list保存了(x, -y, value)三元组的方式,可以直接使用sort进行排序。这样带来的麻烦是需要使用比较前后两个相邻的三元组对应的x值是否相等来判断是否放到同一个列的list中,代码如下:

# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution(object):
def verticalTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
self.m_ = list()
self.dfs(root, 0, 0)
self.m_.sort()
res = [[self.m_[0][2]]]
for i in range(1, len(self.m_)):
if self.m_[i][0] == self.m_[i - 1][0]:
res[-1].append(self.m_[i][2])
else:
res.append([self.m_[i][2]])
return res def dfs(self, root, x, y):
if not root: return
self.m_.append((x, -y, root.val))
self.dfs(root.left, x - 1, y - 1)
self.dfs(root.right, x + 1, y - 1)

BFS

这个题同样也可以使用BFS来解决,通过维护一个队列,我们从上到下依次遍历每个节点,给每个节点设置好了坐标。这个队列存储的是个三元组(TreeNode*,int x,int y)做法和DFS的方法极其类似,就不再详细讲了。

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> verticalTraversal(TreeNode* root) {
queue<pair<TreeNode*, pair<int, int>>> q; // node, x, y
q.push(make_pair(root, make_pair(0, 0)));
map<int, vector<pair<int, int>>> nodeMap;
while (!q.empty()) {
auto d = q.front(); q.pop();
TreeNode* curNode = d.first;
int x = d.second.first;
int y = d.second.second;
nodeMap[x].emplace_back(-y, curNode->val);
if (curNode->left)
q.push(make_pair(curNode->left, make_pair(x - 1, y - 1)));
if (curNode->right)
q.push(make_pair(curNode->right, make_pair(x + 1, y - 1)));
}
vector<vector<int>> res;
for (auto nm : nodeMap) {
sort(nm.second.begin(), nm.second.end());
vector<int> cols;
for (auto p : nm.second)
cols.push_back(p.second);
res.push_back(cols);
}
return res;
}
};

python版本的BFS如下,同样是先把所有的节点遍历一遍并保存每个节点的位置,然后根据位置再排序遍历求解的方式做到的。

# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None class Solution(object):
def verticalTraversal(self, root):
"""
:type root: TreeNode
:rtype: List[List[int]]
"""
q = collections.deque()
q.append((root, 0, 0))
m_ = list()
while q:
node, x, y = q.popleft()
m_.append((x, -y, node.val))
if node.left:
q.append((node.left, x - 1, y - 1))
if node.right:
q.append((node.right, x + 1, y - 1))
m_.sort()
res = [[m_[0][2]]]
for i in range(1, len(m_)):
if m_[i][0] == m_[i - 1][0]:
res[-1].append(m_[i][2])
else:
res.append([m_[i][2]])
return res

日期

2019 年 2 月 20 日 —— 少刷知乎多做题

【LeetCode】987. Vertical Order Traversal of a Binary Tree 解题报告(C++ & Python)的更多相关文章

  1. LeetCode 987. Vertical Order Traversal of a Binary Tree

    原题链接在这里:https://leetcode.com/problems/vertical-order-traversal-of-a-binary-tree/ 题目: Given a binary ...

  2. 【leetcode】987. Vertical Order Traversal of a Binary Tree

    题目如下: Given a binary tree, return the vertical order traversal of its nodes values. For each node at ...

  3. LC 987. Vertical Order Traversal of a Binary Tree

    Given a binary tree, return the vertical order traversal of its nodes values. For each node at posit ...

  4. 【LeetCode】958. Check Completeness of a Binary Tree 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 BFS DFS 日期 题目地址:https://le ...

  5. 【LeetCode】637. Average of Levels in Binary Tree 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 方法一:DFS 方法二:BFS 日期 题目地址:ht ...

  6. 【LeetCode】863. All Nodes Distance K in Binary Tree 解题报告(Python)

    [LeetCode]863. All Nodes Distance K in Binary Tree 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http ...

  7. 【LeetCode】331. Verify Preorder Serialization of a Binary Tree 解题报告(Python)

    [LeetCode]331. Verify Preorder Serialization of a Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...

  8. 【LeetCode】297. Serialize and Deserialize Binary Tree 解题报告(Python)

    [LeetCode]297. Serialize and Deserialize Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode ...

  9. 【LeetCode】662. Maximum Width of Binary Tree 解题报告(Python)

    [LeetCode]662. Maximum Width of Binary Tree 解题报告(Python) 标签(空格分隔): LeetCode 题目地址:https://leetcode.co ...

随机推荐

  1. cpu的性能测试

    #!/bin/bash #user%加上sys%是性能的评判标准 User_sys_a=`sar -u 1 3 |tail -1 |awk '{print $3"+"$5}'|bc ...

  2. 硬盘SSD、HDD和SSHD都是什么意思?哪种类型硬盘最好?

    硬盘分类:(1)HHD 机械硬盘(Mechanical hard disk)(2)SSD 固态硬盘(solid state drive/disk)(3)SSHD 混合硬盘,说白了就是HDD+SSD=S ...

  3. mysql 不等于 符号写法

    今天在写sql语句的时候,想确认下mysql的不等于运算符是用什么符号表示的 经过测试发现mysql中用<>与!=都是可以的,但sqlserver中不识别!=,所以建议用<> ...

  4. 选择省份、选择省市区举例【c#】【js】

    <style type="text/css"> .labelhide { -webkit-box-shadow: 0px 1px 0px 0px #f3f3f3 !im ...

  5. 扩展kmp 学习笔记

    学习了一下这个较为冷门的知识,由于从日报开始看起,还是比较绕的-- 首先定义 \(Z\) 函数表示后缀 \(i\) 与整个串的 \(lcp\) 长度 一个比较好的理解于实现方式是类似于 \(manac ...

  6. Qt——error之undefined reference to `vtable for classname

    可能原因:自定义类中使用自定义槽和信号,但是没有在类中增加Q_OBJECT, 解决办法:在类中增加Q_OBJECT,删除编译产生的文件进行重新编译 具体原因分析如下 博主原文

  7. C++之error: cannot bind non-const lvalue reference of type ‘myString&’ to an rvalue of type ‘myString’

    先看代码(不想看代码可以直接看代码后的问题描述) //header.h #ifndef _HEADER_H #define _HEADER_H #define defaultSize 128 #inc ...

  8. MySQL学习(一)——创建新用户、数据库、授权

    一.创建用户 1.登录mysql mysql -u root -p 2.创建本地用户>/font> use mysql; //选择mysql数据库 create user 'test'@' ...

  9. Linux基础命令---ntpq查询时间服务器

    ntpq ntpq指令使用NTP模式6数据包与NTP服务器通信,能够在允许的网络上查询的兼容的服务器.它以交互模式运行,或者通过命令行参数运行. 此命令的适用范围:RedHat.RHEL.Ubuntu ...

  10. Dos窗口下中文乱码问题

    最近用Datax工具进行数据同步时,在DOS窗口下出现了中文乱码问题,导致一些错误只能到Log中查看,在网上找了一些方法,记录使用成功的方法. Dos命令:chcp 通过cmd进入Dos命令窗口,执行 ...