【每日一题】1993. 树上的操作

文章目录

  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一:深度优先搜索
  • 写在最后

Tag

【深度优先搜索】【树】【设计数据结构】【2023-09-23】


题目来源

1993. 树上的操作


题目解读

本题是一个设计类的题目,对于设计类的题目就一步步的实现题目要求的成员方法即可。

LockingTree(int[] parent):用父节点数组初始化数据结构以及实现这个类的你需要的数据的初始化相关操作。

lock(int num, int user):如果 iduser 的用户可以给节点 num 上锁,那么返回 true,否则返回 false。如果可以执行此操作,节点 num 会被 iduser 的用户 上锁 。

unlock(int num, int user):如果 iduser 的用户可以给节点 num 解锁,那么返回 true ,否则返回 false。如果可以执行此操作,节点 num 变为 未上锁 状态。

upgrade(int num, int user):如果 iduser 的用户可以给节点 num 升级,那么返回 true,并且给该节点的所有子孙节点解锁即升级操作,否则返回 false。如果可以执行此操作,节点 num 会被升级 。
判断节点 num 是否可以升级有三个要求:

  • 节点 num 当前状态为未上锁;
  • 节点 num 至少有一个未上锁的子孙节点;
  • 节点 num 没有任何上锁的祖先节点。

解题思路

今天又是认真学习 官方题解 的一天!

方法一:深度优先搜索

需要给节点上锁与解锁,但是需要先判断节点 num 的状态,于是可以想到使用一个数组 lockNodeUser 来记录节点的状态:

  • 如果 lockNodeUser[num] = -1,表示节点 num 出于未上锁状态;
  • 如果 lockNodeUser[num] 等于某个非 -1 的数,表示节点 num 处于某个用户的锁定状态。

实现成员方法 lock()

如果 lockNodeUser[num] = -1,表示节点 num 出于未上锁状态,我们可以通过给 lockNodeUser[num] 赋值的方式来实现上锁,并返回 true。否则,直接返回 false,因为当前当前节点已经被上锁了,无法再次上锁。

实现成员方法 unlock()

如果 lockNodeUser[num] 等于指定 user,表示节点 num 处于用户 user 的锁定状态,我们可以进行解锁即给 lockNodeUser[num] 赋值 -1,并返回 true;否则表示用户 user 不能给该节点解锁,直接返回 false

实现成员方法 upgrade()

升级操作的成员方法实现起来相对复杂,首先需要判断三个条件是否同时满足,如果是,还需要给节点 num 上锁并把它所有的子孙节点解锁。

首先,看第一个条件,需要判断节点 num 是否处于未上述状态,这个很容易判断,通过 lockNodeUser[num] 是否等于 -1 即可判断:若等于说明处于未上锁状态,否则处于上锁状态。

第二个条件要求节点 num 没有任何上锁的祖先节点,这个也好判断,从节点 num 自底向上搜索 lockNodeUser[parent[num]] 的值:

  • 如果不等于 -1,说明有个祖先上锁了;
  • 若一直向上搜索到根节点了一直都等于 -1,说明节点 num 没有任何祖先节点上锁。

第三个条件节点 num 是否至少有一个上锁的子孙节点,我们将这一条放在最后来判断是希望和这三个条件都满足时需要执行的 “给节点 num 的所有子孙节点解锁一起实现”。我们定义一个递归函数 checkAndUnlockDescendant() 来实现判断加实现。如果第三个条件也满足了,我们通过递归函数实现了 “给节点 num 的所有子孙节点解锁”;如果第三个条件不满足了,我们也通过递归函数实现了 “给节点 num 的所有子孙节点解锁”,这样不会出错吗?当第三步为假,就说明指定节点没有上锁的子孙节点,那么我们仍可以进行「给它的所有子孙节点解锁」这一步,就相当于此时的解锁是无效操作了。

实现第三个条件的递归函数返回一个布尔值表示当前节点是否有上锁的子孙节点(也包括自己),同时将所有的子孙节点(也包括自己)解锁。首先,通过 lockNodeUser[num] != -1 来判断,是否上锁,如果该不等式成立表示上锁,然后解锁,并递归给子孙解锁。

实现代码

class LockingTree {
private:vector<int> parent;vector<int>lockNodeUser;vector<vector<int>> children;public:LockingTree(vector<int>& parent) {int n = parent.size();this->parent = parent;this->lockNodeUser = vector<int>(n, -1);        // 初始化上锁状态this->children = vector<vector<int>>(n);        // 记录每个父亲的儿子(注意不是所有子孙)for (int i = 0; i < n; ++i) {int p = parent[i];if (p != -1)children[p].push_back(i);}}bool lock(int num, int user) {if (lockNodeUser[num] == -1) {lockNodeUser[num] = user;return true;}return false;}bool unlock(int num, int user) {if (lockNodeUser[num] == user) {lockNodeUser[num] = -1;return true;}return false;}bool hasLockedAncestor(int num) {num = parent[num];while (num != -1) {if (lockNodeUser[num] != -1) {return true;}num = parent[num];}return false;}bool checkAndUnlockDescendant(int num) {bool res = lockNodeUser[num] != -1;lockNodeUser[num] = -1;for (int child : children[num]) {res |= checkAndUnlockDescendant(child);}return res;}bool upgrade(int num, int user) {bool res = lockNodeUser[num] == -1 && !hasLockedAncestor(num) && checkAndUnlockDescendant(num);if (res) {lockNodeUser[num] = user;} return res;}
};/*** Your LockingTree object will be instantiated and called as such:* LockingTree* obj = new LockingTree(parent);* bool param_1 = obj->lock(num,user);* bool param_2 = obj->unlock(num,user);* bool param_3 = obj->upgrade(num,user);*/

复杂度分析

时间复杂度:初始化:构建 children 消耗 O ( n ) O(n) O(n)LockUnlock 都消耗 O ( 1 ) O(1) O(1)Upgrade 消耗 O ( n ) O(n) O(n)

空间复杂度:初始化消耗 O ( n ) O(n) O(n)LockUnlock 都消耗 O ( 1 ) O(1) O(1)Upgrade 消耗 O ( n ) O(n) O(n)


写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/86563.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【ACDC数据集】:预处理ACDC心脏3D MRI影像数据集到VOC数据集格式,nii转为jpg,label转为png

【Segment Anything Model】做分割的专栏链接&#xff0c;欢迎来学习。 【博主微信】cvxiaoyixiao 本专栏为公开数据集的预处理&#xff0c;持续更新中。 文章目录 1️⃣ ACDC数据集介绍2️⃣ ACDC数据集样例 3️⃣ 预处理ACDC目标 4️⃣ 处理结果样图 5️⃣ 代码 6️⃣ 划分测…

Maven高级---分模块设计,继承(继承关系/版本锁定/自定义属性)

目录 分模块设计 继承与聚合 继承关系 ​案例​ 版本锁定 自定义属性/引用属性 分模块设计 把一个项目拆分成不同的模块 我们可以把原来一个项目包中的东西单独提出来作为一个模块,也是解耦的思想 然后我们可以通过引入依赖的方式将这两个模块引入,如下 继承与聚合 继…

xxe攻击(XML外部实体)

1.定义 XML用于标记电子文件使其具有结构性的标记语言&#xff0c;可以用来标记数据、定义数据类型&#xff0c;是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义&#xff08;可选&#xff09;、文档元素。 http://www.w3school.com.…

初识操作系统

目录 一.操作系统的概念 二.正确理解“管理” 三.操作系统对硬件进行管理 四.系统调用接口 五.用户操作接口 一.操作系统的概念 操作系统是一款进行软硬件资源管理的软件 现在我们知道了操作系统的概念了&#xff0c;那么为什么要有操作系统呢&#xff1f; 操作系统将软…

李宏毅hw-9:Explainable ML

——欲速则不达&#xff0c;我已经很幸运了&#xff0c;只要珍惜这份幸运就好了&#xff0c;不必患得患失&#xff0c;慢慢来。 ----查漏补缺&#xff1a; 1.关于这个os.listdir的使用 2.从‘num_文件名.jpg’中提取出数值&#xff1a; 3.slic图像分割标记函数的作用&#xf…

光电探测器怎么选

光电探测器&#xff0c;也称为PD&#xff08;photodetector&#xff09; 基本原理是&#xff0c;光信号进入光电探测器转换为电压信号&#xff0c;这个电压信号会很弱&#xff0c;微伏或者毫伏级别。 所以PD分为带放大和不带放大 带放大呢&#xff0c;是因为信号太弱&#xf…

Vue系列(二)之 基础语法上篇【插值,指令,过滤器,计算属性监听属性】以及购物车实现

目录 一. 插值 1.1 文本 1.2 原始HTML 1.3 属性 1.4 表达式 二. 指令 2.1 v-if/v-else-if/v-else指令 2.2 v-show指令 2.3 v-for指令 2.4 下拉框/复选框 2.5 动态参数 三. 过滤器 3.1 局部过滤器基本应用 3.2 局部过滤器串行使用 3.3 局部过滤器传参 3.4 全局过…

QT学习之创建项目

1、添加快捷键到桌面 找到所在安装路径Qt5.14.1\Tools\QtCreator\bin添加至桌面 双击后打开 2、创建项目 点击下一步 再点击下一步 下一步 当前暂时选择32位&#xff0c;之后点击完成 3、进入编辑页面并运行 运行快捷键&#xff1a;CtrlR 运行界面点击按钮&#xff1a; 运行…

单臂路由的详细配置步骤

1、单臂路由概述 单臂路由&#xff08;router-on-a-stick&#xff09;是指在路由器的一个接口上通过配置子接口&#xff08;或“逻辑接口”&#xff0c;并不存在真正物理接口&#xff09;的方式&#xff0c;实现原来相互隔离的不同VLAN&#xff08;虚拟局域网&#xff09;之间…

C++笔记之引用折叠规则

C笔记之引用折叠规则 文章目录 C笔记之引用折叠规则1. 当两个左值引用结合在一起时&#xff0c;它们会折叠成一个左值引用。2. 当一个左值引用和一个右值引用结合在一起时&#xff0c;它们会折叠成一个左值引用。3. 当两个右值引用结合在一起时&#xff0c;它们也会折叠成一个右…

【网络协议】Http-上

Http请求结构&#xff1a; 结构图1&#xff1a; 实验解析请求报文&#xff1a; 1.在Edge浏览器上输入ip地址端口号文件资源&#xff0c;也就是下图中的120.XX.139.29:8888/A/B/c.html 2.我的程序接收到了一个没有有效载荷的http请求(呼应上面的结构图1)&#xff0c;如下 GET …

Python机器学习实战-特征重要性分析方法(1):排列重要性(附源码和实现效果)

实现功能 排列重要性 PermutationImportance&#xff1a;该方法会随机排列每个特征的值&#xff0c;然后监控模型性能下降的程度。如果获得了更大的下降意味着特征更重要 实现代码 from sklearn.datasets import load_breast_cancer from sklearn.ensemble import RandomFore…

C语言之字符函数字符串函数篇(2)

目录 字符串查找 strstr strstr的使用 strstr的模拟实现 分析 考虑点 代码 strt strtok的使用 循环改进 错误信息报告 strerror 错误码的错误信息 strerror的使用 perror 字符操作 字符分类函数 字符转化函数 今天我们接着讲字符串函数&#xff0c;也…

balenaEtcher格式化的U盘恢复原来样子

今天用balenaEtcher烧录了U盘&#xff0c;刷机N1盒子openwrt, 刷完机结果发现自己的U盘电脑最后只有167M 想要恢复原来的64G以下是方法&#xff0c;使用win10系统 1、打开命令行cmd&#xff08;winr打开运行&#xff0c;在其中输入cmd就可以打开&#xff09;&#xff1b; 2…

C++QT day11

绘制时钟 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent>//绘制事件类 #include <QDebug>//信息调试类 #include <QPainter>//画家类 #include <QTimer>//定时器类 #include <QTime> #include &…

Android---打开相机拍照

简单实现打开系统系统相机拍一张图片并显示在UI上&#xff0c;适用与个人主页头像的切换。 1. 添加权限。AndroidManifest.xml里添加使用相机的权限。 <uses-permission android:name"android.permission.CAMERA"/> 2. 布局。布局内容比较交单&#xff0c;一…

leetcode21合并两个有序链表

题目&#xff1a; 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]示例 2&#xff1a; 输入&#xff1a;l1 [], l2 [] 输…

智慧农业农场小程序源码 智慧农场系统源码

智慧农业农场小程序源码 智慧农场系统源码 一、 智慧农场系统的组成 智慧农场系统一般包括传感器、控制器、数据采集与处理平台、应用软件等组成部分。其中, 传感器主要用于采集土壤温度、湿度、光照强度等环境参数,以及作物生长状态、水肥情况等生产信息。控制器则根据传感器…

一个关于 i++ 和 ++i 的面试题打趴了所有人

前言 都说大城市现在不好找工作&#xff0c;可小城市却也不好招人。 我们公司招了挺久都没招到&#xff0c;主管感到有些心累。 我提了点建议&#xff0c;是不是面试问的太深了&#xff0c;在这种小城市&#xff0c;能干活就行。 他说自己问的面试题都很浅显&#xff0c;如果答…