2023-06-06:给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。 对位于 (row, col) 的每个结点而言, 其左右子结点分别位于 (row + 1, col -
2023-06-06:给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。
对位于 (row, col) 的每个结点而言,
其左右子结点分别位于 (row + 1, col - 1) 和 (row + 1, col + 1)
树的根结点位于 (0, 0) 。
二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,
形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,
则按结点的值从小到大进行排序。
返回二叉树的 垂序遍历 序列。
输入:root = [3,9,20,null,null,15,7]。
输出:[[9],[3,15],[20],[7]]。
答案2023-06-06:
大体过程如下:
1 定义结构体TreeNode
表示二叉树节点,包含属性Val
表示节点值和Left
和Right
分别表示左右节点。
2.定义结构体Info
表示节点信息,包含属性row
、col
和val
分别表示节点所在的行、列和值。
3.定义函数NewInfo()
创建节点信息。
4.定义切片类型ByColThenRowThenVal
并实现其三个方法Len()
、Less()
和Swap()
使之按列、行和节点值排序。
5.定义函数verticalTraversal()
实现二叉树的垂序遍历。
6.在verticalTraversal()
中,创建切片collects
存储各节点信息,并将根节点的信息存入其中。
7.调用函数dfs()
遍历整个二叉树,添加各节点的信息到collects
中。
8.对collects
按列、行和节点值排序。
9.遍历collects
,将同列的所有节点值存入一个新的子切片,将子切片添加到答案ans
中。
10.返回答案ans
。
时间复杂度是O(nlogn),其中n是节点数。n个节点需要遍历一次,排序时间复杂度是O(nlogn)。所以总时间复杂度是O(nlogn)。
空间复杂度是O(n),其中n是节点数。需要使用切片collects来存储节点的信息,collects的长度最大是n,所以空间复杂度是O(n)。
golang完整代码如下:
package main
import (
"fmt"
"sort"
)
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
type Info struct {
row int
col int
val int
}
func NewInfo(r, c, v int) Info {
return Info{row: r, col: c, val: v}
}
type ByColThenRowThenVal []Info
func (bc ByColThenRowThenVal) Len() int { return len(bc) }
func (bc ByColThenRowThenVal) Less(i int, j int) bool {
if bc[i].col != bc[j].col {
return bc[i].col < bc[j].col
}
if bc[i].row != bc[j].row {
return bc[i].row < bc[j].row
}
return bc[i].val < bc[j].val
}
func (bc ByColThenRowThenVal) Swap(i int, j int) { bc[i], bc[j] = bc[j], bc[i] }
func verticalTraversal(root *TreeNode) [][]int {
collects := make([]Info, 0, 1000)
rootInfo := NewInfo(0, 0, root.Val)
collects = append(collects, rootInfo)
dfs(root, rootInfo, &collects)
sort.Sort(ByColThenRowThenVal(collects))
ans := make([][]int, 0, 1000)
for i := 0; i < len(collects); i++ {
if i == 0 || collects[i-1].col != collects[i].col {
ans = append(ans, []int{})
}
ans[len(ans)-1] = append(ans[len(ans)-1], collects[i].val)
}
return ans
}
func dfs(root *TreeNode, rootInfo Info, collects *[]Info) {
if root.Left != nil {
leftInfo := NewInfo(rootInfo.row+1, rootInfo.col-1, root.Left.Val)
*collects = append(*collects, leftInfo)
dfs(root.Left, leftInfo, collects)
}
if root.Right != nil {
rightInfo := NewInfo(rootInfo.row+1, rootInfo.col+1, root.Right.Val)
*collects = append(*collects, rightInfo)
dfs(root.Right, rightInfo, collects)
}
}
func main() {
leaf7 := &TreeNode{7, nil, nil}
leaf15 := &TreeNode{15, nil, nil}
leaf20 := &TreeNode{20, leaf15, leaf7}
leaf9 := &TreeNode{9, nil, nil}
root := &TreeNode{3, leaf9, leaf20}
result := verticalTraversal(root)
fmt.Println(result)
}
c++完整代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
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) {}
};
struct Info {
int row;
int col;
int val;
Info(int r, int c, int v) {
row = r;
col = c;
val = v;
}
};
struct InfoComparator {
bool operator() (const Info& o1, const Info& o2) {
if (o1.col != o2.col) {
return o1.col < o2.col;
}
if (o1.row != o2.row) {
return o1.row < o2.row;
}
return o1.val < o2.val;
}
};
void dfs(TreeNode* root, Info rootInfo, vector<Info>& collects) {
if (root->left != nullptr) {
Info leftInfo(rootInfo.row + 1, rootInfo.col - 1, root->left->val);
collects.push_back(leftInfo);
dfs(root->left, leftInfo, collects);
}
if (root->right != nullptr) {
Info rightInfo(rootInfo.row + 1, rootInfo.col + 1, root->right->val);
collects.push_back(rightInfo);
dfs(root->right, rightInfo, collects);
}
}
vector<vector<int>> verticalTraversal(TreeNode* root) {
vector<Info> collects;
Info rootInfo(0, 0, root->val);
collects.push_back(rootInfo);
dfs(root, rootInfo, collects);
sort(collects.begin(), collects.end(), InfoComparator());
vector<vector<int>> ans;
for (int i = 0; i < collects.size(); i++) {
if (i == 0 || collects[i - 1].col != collects[i].col) {
ans.push_back(vector<int>());
}
ans.back().push_back(collects[i].val);
}
return ans;
}
int main() {
TreeNode* leaf7 = new TreeNode(7);
TreeNode* leaf15 = new TreeNode(15);
TreeNode* leaf20 = new TreeNode(20, leaf15, leaf7);
TreeNode* leaf9 = new TreeNode(9);
TreeNode* root = new TreeNode(3, leaf9, leaf20);
vector<vector<int>> result = verticalTraversal(root);
for (int i = 0; i < result.size(); i++) {
for (int j = 0; j < result[i].size(); j++) {
cout << result[i][j] << " ";
}
cout << endl;
}
return 0;
}
2023-06-06:给你二叉树的根结点 root ,请你设计算法计算二叉树的 垂序遍历 序列。 对位于 (row, col) 的每个结点而言, 其左右子结点分别位于 (row + 1, col -的更多相关文章
- 【2】【leetcode-105,106】 从前序与中序遍历序列构造二叉树,从中序与后序遍历序列构造二叉树
105. 从前序与中序遍历序列构造二叉树 (没思路,典型记住思路好做) 根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [ ...
- [Swift]LeetCode987. 二叉树的垂序遍历 | 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 ...
- [PHP] 算法-根据前序和中序遍历结果重建二叉树的PHP实现
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5 ...
- 【leetcode 105. 从前序与中序遍历序列构造二叉树】解题报告
前往 中序,后序遍历构造二叉树, 中序,前序遍历构造二叉树 TreeNode* build(vector<int>& preorder, int l1, int r1, vecto ...
- 【leetcode 106. 从中序与后序遍历序列构造二叉树】解题报告
前往 中序,后序遍历构造二叉树, 中序,前序遍历构造二叉树 TreeNode* build(vector<int>& inorder, int l1, int r1, vector ...
- 已知前序(后序)遍历序列和中序遍历序列构建二叉树(Leetcode相关题目)
1.文字描述: 已知一颗二叉树的前序(后序)遍历序列和中序遍历序列,如何构建这棵二叉树? 以前序为例子: 前序遍历序列:ABCDEF 中序遍历序列:CBDAEF 前序遍历先访问根节点,因此前序遍历序列 ...
- leetcode 105 106 从前序与中序遍历序列构造二叉树 从中序与后序遍历序列构造二叉树
题目: 105 根据一棵树的前序遍历与中序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = ...
- LeetCode 中级 - 从前序与中序遍历序列构造二叉树(105)
一个前序遍历序列和一个中序遍历序列可以确定一颗唯一的二叉树. 根据前序遍历的特点, 知前序序列(PreSequence)的首个元素(PreSequence[0])为二叉树的根(root), 然后在中 ...
- 【LeetCode】105#从前序与中序遍历序列构造二叉树
题目描述 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9 ...
- LeetCode 106. 从中序与后序遍历序列构造二叉树(Construct Binary Tree from Inorder and Postorder Traversal)
题目描述 根据一棵树的中序遍历与后序遍历构造二叉树. 注意:你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9 ...
随机推荐
- Mysql 事务隔离级别和锁的关系
我们都知道事务的几种性质,数据库为了维护这些性质,尤其是一致性和隔离性,一般使用加锁这种方式.同时数据库又是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力.所以对于 ...
- HashMap和ConcurrentHashMap扩容过程
HashMap 存储结构 HashMap是数组+链表+红黑树(1.8)实现的. (1)Node[] table,即哈希桶数组.Node是内部类,实现了Map.Entry接口,本质是键值对. 下图链表中 ...
- 购物车,实现增删改查;无bug,还有一个直接修改购物车数量功能未实现
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Linux中Python自动输入sudo 密码【管道 sudo参数 stdin&stdout】
一.背景和需求 背景: 由于docker服务进程都是以root帐号的身份运行的,所以用docker跑abpred出来的文件所有者都是root, 而我作为一般用户,操作这个文件不够权限,运行代码时需要s ...
- 关于java.lang.Object类、equals()、toString()的使用、以及方法得重载和重写得一些笔记
java.lang.Object类 * 1.Object类是所有Java类的根父类; * 2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为java.lang.Object类 * ...
- [Java SE]javac编译时编码错误
1 问题复现 Information:java: javacTask: 源发行版 8 需要目标发行版 1.8 Information:java: Errors occurred while compi ...
- [数据库]MySQL之备份与恢复【未完待续】
1 恢复 方式一 source sqlFile.sql 登陆MySQL 创建数据库db (create database db;) 进入/使用 数据库db (use db;) 将要导入的sql文件放到 ...
- 在IIS 搭建FTP站点
最近在项目中需要用到FTP,需要将生成的文件通过FTP上传网站. 在此记录下. FTP SSL设置,需要允许SSL连接. FTP 身份验证,匿名身份验证需要启用. FTP 授权规则,如果没有特殊情况允 ...
- Vite-Admin后台管理系统|vite4+vue3+pinia前端后台框架实例
基于vite4.x+vue3+pinia前端后台管理系统解决方案ViteAdmin. 前段时间分享了一篇vue3自研pc端UI组件库VEPlus.这次带来最新开发的基于vite4+vue3+pinia ...
- 【SSM项目】尚筹网(三)基于Servlet3.0项目搭建:异常映射和拦截器机制
1 异常映射 1.1 目标 使用异常映射对项目的异常和错误提示进行统一管理. 1.2 思路 对于普通的页面请求,异常映射机制捕获到handler方法抛出的异常后会响应为一个错误页面,对于处理ajax请 ...