2023-05-03:给你一棵 二叉树 的根节点 root ,树中有 n 个节点 每个节点都可以被分配一个从 1 到 n 且互不相同的值 另给你一个长度为 m 的数组 queries 你必须在树上执行
2023-05-03:给你一棵 二叉树 的根节点 root ,树中有 n 个节点
每个节点都可以被分配一个从 1 到 n 且互不相同的值
另给你一个长度为 m 的数组 queries
你必须在树上执行 m 个 独立 的查询,其中第 i 个查询你需要执行以下操作:
从树中 移除 以 queries[i] 的值作为根节点的子树
题目所用测试用例保证 queries[i] 不 等于根节点的值。
返回一个长度为 m 的数组 answer ,其中 answer[i] 是执行第 i 个查询后树的高度。
注意:
查询之间是独立的,所以在每个查询执行后,树会回到其 初始 状态。
树的高度是从根到树中某个节点的 最长简单路径中的边数 。
输入:root = [5,8,9,2,1,3,7,4,6], queries = [3,2,4,8]。
输出:[3,2,3,2]。
答案2023-05-03:
大体过程:
1.定义和初始化全局变量
使用常量
MAXN
定义数组大小。定义用于深度优先搜索的四个数组
dfn
、deep
、size
、maxl
、maxr
和一个计数器n
,保存每个节点的编号、深度、子树大小、左右子树的最大深度。
2.定义深度优先搜索函数 dfs
用一个计数器
i
记录当前节点的编号,并将其存储到数组dfn
中。将当前节点的深度
h
存储到数组deep
中。将当前节点的子树大小初始化为 1,存储到数组
size
中。如果当前节点存在左孩子,则递归调用
dfs
函数,并将当前节点的子树大小加上其左孩子的子树大小。如果当前节点存在右孩子,则递归调用
dfs
函数,并将当前节点的子树大小加上其右孩子的子树大小。
3.在主函数中创建一棵二叉树 root
和一个查询数组 queries
。
4.对于每个查询 queries[i]
,执行以下操作:
计算以
queries[i]
为根节点的子树编号范围,即dfn[queries[i]]
到dfn[queries[i]]+size[dfn[queries[i]]]-1
。将该范围内所有节点的深度保存到数组
maxl
中,并计算其前缀最大值。将该范围内所有节点的深度保存到数组
maxr
中,并计算其后缀最大值。计算左右子树的最大深度,取其中的较大值作为删除子树后树的高度。
将结果保存到答案数组
ans
中。
5.返回答案数组。
注意:在每次查询中,需要重新计算左右子树的最大深度,因为每次查询都会修改树的结构。
时间复杂度:
在 dfs
函数中,对于每个节点最多访问一次,因此该函数的时间复杂度为 O(n),其中 n 是二叉树的节点数。
在 treeQueries
函数中,需要处理 $m$ 个查询,对于每个查询需要计算左右子树的最大深度,时间复杂度为 O(n),因此总时间复杂度为 O(mn)。
空间复杂度:
在 C++ 中,数组和变量的空间占用量是固定的,因此空间复杂度主要取决于递归调用时堆栈的空间占用量。由于最坏情况下二叉树可能退化成一个链表,因此堆栈空间的最大使用量为 O(n),其中 n 是二叉树的节点数。
除了堆栈空间之外,还需要使用常量大小的额外空间来存储全局变量和临时变量,因此总空间复杂度为 O(n)。
go完整代码如下:
package main
import (
"fmt"
)
type TreeNode struct {
Val int
Left *TreeNode
Right *TreeNode
}
const MAXN = 100010
var dfn [MAXN]int
var deep [MAXN]int
var size [MAXN]int
var maxl [MAXN]int
var maxr [MAXN]int
var n int
func treeQueries(root *TreeNode, queries []int) []int {
n = 0
dfs(root, 0)
for i := 1; i <= n; i++ {
maxl[i] = max(maxl[i-1], deep[i])
}
maxr[n+1] = 0
for i := n; i >= 1; i-- {
maxr[i] = max(maxr[i+1], deep[i])
}
m := len(queries)
ans := make([]int, m)
for i := 0; i < m; i++ {
leftMax := maxl[dfn[queries[i]]-1]
rightMax := maxr[dfn[queries[i]]+size[dfn[queries[i]]]]
ans[i] = max(leftMax, rightMax)
}
return ans
}
func dfs(head *TreeNode, h int) {
i := n + 1
dfn[head.Val] = i
deep[i] = h
size[i] = 1
n = i
if head.Left != nil {
dfs(head.Left, h+1)
size[i] += size[dfn[head.Left.Val]]
}
if head.Right != nil {
dfs(head.Right, h+1)
size[i] += size[dfn[head.Right.Val]]
}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
func main() {
root := &TreeNode{
Val: 5,
Left: &TreeNode{
Val: 8,
Left: &TreeNode{
Val: 2,
Left: nil,
Right: nil,
},
Right: &TreeNode{
Val: 9,
Left: nil,
Right: nil,
},
},
Right: &TreeNode{
Val: 3,
Left: &TreeNode{
Val: 1,
Left: nil,
Right: nil,
},
Right: &TreeNode{
Val: 7,
Left: &TreeNode{
Val: 4,
Left: nil,
Right: nil,
},
Right: &TreeNode{
Val: 6,
Left: nil,
Right: nil,
},
},
},
}
queries := []int{3, 2, 4, 8}
ans := treeQueries(root, queries)
fmt.Println("The query results are:", ans)
}
c完整代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 100010
struct TreeNode {
int val;
struct TreeNode* left;
struct TreeNode* right;
};
int dfn[MAXN];
int deep[MAXN];
int size[MAXN];
int maxl[MAXN];
int maxr[MAXN];
int n;
int max0(int a, int b) {
return a > b ? a : b;
}
void dfs(struct TreeNode* head, int h);
int* treeQueries(struct TreeNode* root, int* queries, int queriesSize, int* returnSize);
int main() {
struct TreeNode node9 = { 9, NULL, NULL };
struct TreeNode node8 = { 8, NULL, &node9 };
struct TreeNode node2 = { 2, NULL, NULL };
struct TreeNode node4 = { 4, NULL, NULL };
struct TreeNode node1 = { 1, NULL, NULL };
struct TreeNode node6 = { 6, NULL, NULL };
struct TreeNode node7 = { 7, &node4, &node6 };
struct TreeNode node3 = { 3, &node1, &node7 };
struct TreeNode node5 = { 5, &node8, &node3 };
struct TreeNode* root = &node5;
int queries[] = { 3, 2, 4, 8 };
int queriesSize = sizeof(queries) / sizeof(int);
int returnSize = 0;
int* ans = treeQueries(root, queries, queriesSize, &returnSize);
printf("The query results are: [");
for (int i = 0; i < returnSize; i++) {
if (i > 0) {
printf(", ");
}
printf("%d", ans[i]);
}
printf("]\n");
free(ans);
return 0;
}
void dfs(struct TreeNode* head, int h) {
int i = ++n;
dfn[head->val] = i;
deep[i] = h;
size[i] = 1;
if (head->left != NULL) {
dfs(head->left, h + 1);
size[i] += size[dfn[head->left->val]];
}
if (head->right != NULL) {
dfs(head->right, h + 1);
size[i] += size[dfn[head->right->val]];
}
}
int* treeQueries(struct TreeNode* root, int* queries, int queriesSize, int* returnSize) {
n = 0;
dfs(root, 0);
int i;
for (i = 1; i <= n; i++) {
maxl[i] = max0(maxl[i - 1], deep[i]);
}
maxr[n + 1] = 0;
for (i = n; i >= 1; i--) {
maxr[i] = max0(maxr[i + 1], deep[i]);
}
int* ans = (int*)malloc(queriesSize * sizeof(int));
for (i = 0; i < queriesSize; i++) {
int leftMax = maxl[dfn[queries[i]] - 1];
int rightMax = maxr[dfn[queries[i]] + size[dfn[queries[i]]]];
ans[i] = max0(leftMax, rightMax);
}
*returnSize = queriesSize;
return ans;
}
c++完整代码如下:
#include <iostream>
#include <vector>
using namespace std;
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
const int MAXN = 100010;
int dfn[MAXN];
int deep[MAXN];
int size0[MAXN];
int maxl[MAXN];
int maxr[MAXN];
int n;
void dfs(TreeNode* head, int h) {
int i = ++n;
dfn[head->val] = i;
deep[i] = h;
size0[i] = 1;
if (head->left != nullptr) {
dfs(head->left, h + 1);
size0[i] += size0[dfn[head->left->val]];
}
if (head->right != nullptr) {
dfs(head->right, h + 1);
size0[i] += size0[dfn[head->right->val]];
}
}
vector<int> treeQueries(TreeNode* root, vector<int>& queries) {
n = 0;
dfs(root, 0);
for (int i = 1; i <= n; i++) {
maxl[i] = max(maxl[i - 1], deep[i]);
}
maxr[n + 1] = 0;
for (int i = n; i >= 1; i--) {
maxr[i] = max(maxr[i + 1], deep[i]);
}
int m = (int)queries.size();
vector<int> ans(m);
for (int i = 0; i < m; i++) {
int leftMax = maxl[dfn[queries[i]] - 1];
int rightMax = maxr[dfn[queries[i]] + size0[dfn[queries[i]]]];
ans[i] = max(leftMax, rightMax);
}
return ans;
}
int main() {
TreeNode node9(9);
TreeNode node8(8);
node8.right = &node9;
TreeNode node2(2);
TreeNode node4(4);
TreeNode node1(1);
TreeNode node6(6);
TreeNode node7(7);
node7.left = &node4;
node7.right = &node6;
TreeNode node3(3);
node3.left = &node1;
node3.right = &node7;
TreeNode node5(5);
node5.left = &node8;
node5.right = &node3;
vector<int> queries{ 3, 2, 4, 8 };
auto ans = treeQueries(&node5, queries);
cout << "The query results are: [";
for (int i = 0; i < ans.size(); i++) {
if (i > 0) {
cout << ", ";
}
cout << ans[i];
}
cout << "]" << endl;
return 0;
}
2023-05-03:给你一棵 二叉树 的根节点 root ,树中有 n 个节点 每个节点都可以被分配一个从 1 到 n 且互不相同的值 另给你一个长度为 m 的数组 queries 你必须在树上执行的更多相关文章
- 点击一个div ,把div里的某个参数的值,传到一个input里面
- C++ 推断一棵二叉树是否对称
一棵二叉树对称,就是说它假设以根为轴,翻转过去一样.例如以下图所看到的,以虚线为轴.把左边翻转到右边,各顶点及顶点中的值一一相应. watermark/2/text/aHR0cDovL2Jsb2cuY ...
- 剑指offer17:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
1 题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 2 思路和方法 (1)先在A中找和B的根节点相同的结点 (2)找到之后遍历对应位置的其他结点, ...
- 面试题:给定一个长度为N的数组,其中每个元素的取值范围都是1到N。判断数组中是否有重复的数字
题目:给定一个长度为N的数组,其中每个元素的取值范围都是1到N.判断数组中是否有重复的数字.(原数组不必保留) 方法1.对数组进行排序(快速,堆),然后比较相邻的元素是否相同.时间复杂度为O(nlog ...
- CF E. Vasya and a Tree】 dfs+树状数组(给你一棵n个节点的树,每个点有一个权值,初始全为0,m次操作,每次三个数(v, d, x)表示只考虑以v为根的子树,将所有与v点距离小于等于d的点权值全部加上x,求所有操作完毕后,所有节点的值)
题意: 给你一棵n个节点的树,每个点有一个权值,初始全为0,m次操作,每次三个数(v, d, x)表示只考虑以v为根的子树,将所有与v点距离小于等于d的点权值全部加上x,求所有操作完毕后,所有节点的值 ...
- 前端面试题:不使用loop循环,创建一个长度为100的数组,并且每个元素的值等于它的下标,,怎么实现好?
昨天,看这道题,脑子锈住了,就是没有思路,没看明白是什么意思?⊙﹏⊙|∣今天早上起床,想到需要思考一下这个问题. 当然,我没想明白为什么要这样做?(创建一个长度为100的数组,并且每个元素的值等于它的 ...
- 2021.05.03 T3 数字
2021.05.03 T3 数字 问题描述 一个数字被称为好数字当他满足下列条件: 1. 它有**2*n**个数位,n是正整数(允许有前导0) 2. 构成它的每个数字都在给定的数字集合S中. 3. 它 ...
- 算法进阶面试题05——树形dp解决步骤、返回最大搜索二叉子树的大小、二叉树最远两节点的距离、晚会最大活跃度、手撕缓存结构LRU
接着第四课的内容,加入部分第五课的内容,主要介绍树形dp和LRU 第一题: 给定一棵二叉树的头节点head,请返回最大搜索二叉子树的大小 二叉树的套路 统一处理逻辑:假设以每个节点为头的这棵树,他的最 ...
- 剑指offer38:输入一棵二叉树,求该树的深度
1 题目描述 输入一棵二叉树,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度. 2 思路和方法 深度优先搜索,每次得到左右子树当前最大路径,选择 ...
- 如何一步一步用DDD设计一个电商网站(九)—— 小心陷入值对象持久化的坑
阅读目录 前言 场景1的思考 场景2的思考 避坑方式 实践 结语 一.前言 在上一篇中(如何一步一步用DDD设计一个电商网站(八)—— 会员价的集成),有一行注释的代码: public interfa ...
随机推荐
- dosbox debugger
通过中断看程序运行过程 最终目的是要找到数据保存位置,如何保存到文件的.
- Django数据迁移介绍
1.简介 迁移是 Django 将你对模型的修改(例如增加一个字段,删除一个模型)应用至数据库表结构对方式 2.基本命令 python manage.py migrate---负责应用和撤销迁移 py ...
- vs2019升级到16.8编译报razortaghelper 任务意外失败的错误
为了体验.net 5,把vs升级到了最新版本16.8,然后编译原来的项目(.net core 2.2),报了以下错误: 解决方法如下: 删除C:\Program Files\dotnet\sdk\Nu ...
- Https交互原理
Http超文本传输协议 基于tcp和Ip实现的一种可靠的传输协议,可靠的保证了客户端和服务器之间的传输不会丢失,但是却没办法保证传输数据的安全性. Https是Http的升级版本,用于解决Http数据 ...
- 引用本地的layUI
<script src="/public/vendor/layui-v2.5.6/layui.all.js"></script>
- tornado cgi wsgi uwsgi之间的关系
Tornado可以当作HTTP server,直接TCP开始实现HTTP服务,这也就是为啥说Tornado可以不经过WSGI.实际上它也不是CGI. CGI是指通过stdin和stdout进行HTTP ...
- NodeJs 版本管理
nvm-windows 说明:nvm是Nodejs的版本管理器.在开发中项目可能需要低版本或者高版本的Nodejs运行环境,以此我们可以使用nvm来切换Nodejs的版本. 在安装NVM for Wi ...
- DVWA-File Upload(文件上传)
文件上传是很危险的漏洞,攻击者上传木马到服务器,可以获取服务器的操作权限 LOW 审计源码 <?php if( isset( $_POST[ 'Upload' ] ) ) { // 定义 文件上 ...
- RHEL8使用NMCLI管理网络
使用 NMCLI 配置静态以太网连接 要在命令行上配置以太网连接,请使用 nmcli 工具. 例如,以下流程使用以下设置为 enp7s0 设备创建 NetworkManager 连接配置文件: 静态 ...
- js循环中reduce的用法简单介绍
reduce() 方法接收一个函数作为累加器,reduce 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,接受四个参数:初始值(上一次回调的返回值),当前元素值,当前索引 ...