作者: 负雪明烛
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. Redis高并发处理常见问题及解决方案

    1. 大型电商系统高流量系统设计 场景: 大量电商系统每天要处理上亿请求,其中大量请求来自商品访问.下单.商品的详情是时刻变化,由于请求量过大,不会频繁去服务端获取商品信息,导致服务器压力极大.需要用 ...

  2. mysql—mysql错误Every derived table must have its own alias解决

    Every derived table must have its own alias 这句话的意思是说每个派生出来的表都必须有一个自己的别名. 一般在多表查询时,会出现此错误. 因为,进行嵌套查询的 ...

  3. rabbit mq的php使用 amqp 的支持

    rabbit mq的php使用 php想要操作rabbit 需要扩展amqp 1,先查看自己的php版本 phpinfo() 接下来下载dll文件 地址http://pecl.php.net/pack ...

  4. 4.Reverse Words in a String-Leetcode

    class Solution { public: void reverseWords(string &s) { vector<string> data; string word; ...

  5. 学习java 7.6

    学习内容: 方法重写注意事项:子类不能重写父类的私有方法 子类的访问权限不比父类的低(父类默认,子类可以是默认也可以是public) java中继承的注意事项:java中类只支持单继承,java中类支 ...

  6. Sharding-JDBC 实现水平分表

    1.搭建环 (1) 技术: SpringBoot2.2.1+ MyBatisPlus + Sharding-JDBC + Druid 连接池(2)创建 SpringBoot 工程

  7. Tomcat中的Server.xml配置详解

    Tomcat中的Server.xml配置详解 Tomcat Server的结构图如下: 该文件描述了如何启动Tomcat Server <Server> <Listener /> ...

  8. Can we access global variable if there is a local variable with same name?

    In C, we cannot access a global variable if we have a local variable with same name, but it is possi ...

  9. ubuntu 使用mysql

    一: 安装: sudo apt-get install mysql-serversudo apt-get install mysql-clientsudo apt-get install libmys ...

  10. 【JavaWeb】【JSP】JSP传值到Servlet后端为NULL的问题

    JSP传值到Servlet后端为NULL的问题 哔哩哔哩@萌狼蓝天 博客:萌狼工作室-博客园 联系QQ:#3447902411# | 仅限技术交流可添加 | 添加请说明你的方向和来意 1.目标文件路径 ...