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

news2025/1/12 21:59:25

文章目录

  • 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.coloradmin.cn/o/1037086.html

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

相关文章

Red Hat 8 重置root管理员密码

Linux系统&#xff1a;Red Hat Enterprise Linux release 8.8 (Ootpa) 确定你的Linux系统是否为RHEL 8&#xff08;Red Hat 8&#xff09;系统&#xff0c;在RHEL 8中&#xff0c;选择“活动”–>“终端”命令&#xff0c;然后在打开的终端中输入如下命令&#xff1a; [ro…

2023华为杯数学建模D题-域碳排放量以及经济、人口、能源消费量的现状分析(如何建立指标和指标体系1,碳排放影响因素详细建模过程)

可能建立的指标如下&#xff1a; 经济指标: 地区生产总值&#xff08;GDP&#xff09;人均GDP&#xff1b;第一产业&#xff08;农林部门&#xff09;产值&#xff1b;第二产业&#xff08;能源供应和工业部门&#xff09;产值&#xff1b;第三产业&#xff08;建筑和交通部门…

js中的类型转换

JavaScript 中有两种类型转换&#xff1a;隐式类型转换&#xff08;强制类型转换&#xff09;和显式类型转换。类型转换是将一个数据类型的值转换为另一个数据类型的值的过程。 隐式类型转换&#xff08;强制类型转换&#xff09;&#xff1a; 隐式类型转换是 JavaScript 自动…

【解决】Unity3D中无法在MQTT事件中执行Animator

问题原因&#xff1a; 解决方法&#xff1a; 解决过程 1、在 Unity 中创建一个名为 MainThreadDispatcher 的脚本&#xff0c;用于处理主线程操作。 using System.Collections.Generic; using UnityEngine;public class MainThreadDispatcher : MonoBehaviour {private stati…

基于springboot+vue的华山旅游网(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

【java】【SpringBoot】【四】原理篇 bean、starter、核心原理

目录 一、自动配置 1、bean加载方式&#xff08;复习&#xff09; 1.1 加载方式-xml方式生命bean 1.2 加载方式-xml注解方式声明bean 1.3 注解方式声明配置类 1.4 FactoryBean 1.5 proxyBeanMethod属性 1.6 使用Import注解导入 1.7 使用上下文对象在容器初始化完毕后注…

(第三百篇BLOG记录)写于博士毕业与入职之初-20230924

启 由于若干原因&#xff08;包括但不限于紧锣密鼓的完成博士毕业的一系列实验和论文撰写、学习各种百花齐放的有意思的领域、完成人生身份的重大转变&#xff09;&#xff0c;导致卡在299篇博客已经很久了&#xff0c;不过算了一下还是在一个较长时间维度上可以基本保持每周一…

CompletableFuture-FutureTask

2. CompletableFuture 语雀 2.1 Future接口理论知识复习 Future接口&#xff08;FutureTask实现类&#xff09;定义了操作异步任务执行一些方法&#xff0c;如获取异步任务的执行结果、取消异步任务的执行、判断任务是否被取消、判断任务执行是否完毕等。 举例&#xff1a;…

github pages 部署单页面

github pages介绍 GitHub Pages是一个免费的托管服务&#xff0c;可以直接从GitHub存储库中创建和托管网站。可以使用GitHub Pages来构建自己的网站或为项目生成网站。每个GitHub帐户和组织都可以拥有一个站点&#xff0c;以及无限的项目站点。 主站点的地址就是用户名.githu…

基于springboot+vue的云南旅游网(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

Linux离线安装elasticsearch|header|kibna插件最详细

1.准备软件安装包 [hadoophost152 elasticsearch]$ ll -rw-r--r--. 1 hadoop hadoop 515807354 9月 23 23:40 elasticsearch-8.1.1-linux-x86_64.tar.gz -rw-r--r--. 1 hadoop hadoop 1295593 9月 23 23:48 elasticsearch-head-master.tar.gz -rw-r--r--. 1 hadoop hadoop…

Android修行手册 - Android Studio去掉方法参数提示、变量类型提示、方法引用Usage提示

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

Hudi第一章:编译安装

系列文章目录 Hudi第一章&#xff1a;编译安装 文章目录 系列文章目录前言一、环境准备1.JDK2.Maven1.上传并解压。2.修改源3.添加环境变量 二、hudi编译1.上传解压2.修改pom1.添加仓库2.修改依赖的组件版本 2.修改源码兼容hadoop33.手动安装Kafka依赖1.上传jar包2.install到m…

Linux使用一个脚本启用、停用springboot项目(本文带脚本)

前言 如果仅需要脚本的小伙伴可以下拉至后面&#xff0c;我这里一步一步交大家发布项目 学习之前我们要先会搭建一个项目 可以去看这篇文章&#xff1a;搭建一个SpringBoot项目 一、首先我们配置多环境 0、resources文件如下 1、配置pom.xml文件 <build><!--打包…

uniapp webview实现双向通信

需求&#xff1a;uniapp webview嵌套一个h5 实现双向通信 uniapp 代码 <template><view><web-view src"http://192.168.3.150:9003/" message"onMessage"></web-view></view> </template><script>export defau…

精品基于Python房源爬虫实现数据可视化分析

《[含文档PPT源码等]精品基于Python实现的爬虫实现数据可视化分析》该项目含有源码、文档、PPT、配套开发软件、软件安装教程、项目发布教程等 软件开发环境及开发工具&#xff1a; 开发语言&#xff1a;python 使用框架&#xff1a;Django 前端技术&#xff1a;JavaScript…

JavaScript中的解构赋值

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 对象解构赋值⭐ 数组解构赋值⭐ 默认值和剩余元素⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚…

【面试经典150 | 滑动窗口】长度最小的子数组

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a;暴力枚举方法二&#xff1a;滑动窗口 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些…

stable diffusion模型评价框架

GhostReview:全球第一套AI绘画ckpt评测框架代码 - 知乎大家好&#xff0c;我是_GhostInShell_&#xff0c;是全球AI绘画模型网站Civitai的All Time Highest Rated (全球历史最高评价) 第二名的GhostMix的作者。在上一篇文章&#xff0c;我主要探讨自己关于ckpt的发展方向的观点…

如何模拟自然界生态系统中的食物链

本人最近在研究一款针对青少年儿童的教育游戏&#xff0c;希望从培养孩子各方面的综合素质出发&#xff0c;引导孩子掌握多方面的软知识&#xff0c;软技能。其中有一个比较新颖的游戏玩法------打猎。该玩法创新点在于&#xff0c;引入了食物链的概念。过去一般的游戏里&#…