dfs力扣1993树上的操作

news2024/11/24 17:30:59

文章目录

      • dfs力扣1993树上的操作
        • 题目
        • 示例
        • 提示
        • 做题历程
          • 做题思路
            • 数组定义
            • 编写代码
          • 完整代码

dfs力扣1993树上的操作

题目

题目链接

给你一棵 n 个节点的树,编号从 0n - 1 ,以父节点数组 parent 的形式给出,其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点,所以 parent[0] = -1 ,因为它没有父节点。你想要设计一个数据结构实现树里面对节点的加锁,解锁和升级操作。

数据结构需要支持如下函数:

  • **Lock:**指定用户给指定节点 上锁 ,上锁后其他用户将无法给同一节点上锁。只有当节点处于未上锁的状态下,才能进行上锁操作。

  • **Unlock:**指定用户给指定节点 解锁 ,只有当指定节点当前正被指定用户锁住时,才能执行该解锁操作。

  • Upgrade:指定用户给指定节点 上锁 ,并且将该节点的所有子孙节点 解锁 。只有如下 3 个条件

    全部满足时才能执行升级操作:

    • 指定节点当前状态为未上锁。
    • 指定节点至少有一个上锁状态的子孙节点(可以是 任意 用户上锁的)。
    • 指定节点没有任何上锁的祖先节点。

请你实现 LockingTree 类:

  • LockingTree(int[] parent) 用父节点数组初始化数据结构。
  • lock(int num, int user) 如果 id 为 user 的用户可以给节点 num 上锁,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 会被 id 为 user 的用户 上锁
  • unlock(int num, int user) 如果 id 为 user 的用户可以给节点 num 解锁,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 变为 未上锁 状态。
  • upgrade(int num, int user) 如果 id 为 user 的用户可以给节点 num 升级,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 会被 升级
示例

示例图片

输入:
[“LockingTree”, “lock”, “unlock”, “unlock”, “lock”, “upgrade”, “lock”]
[[[-1, 0, 0, 1, 1, 2, 2]], [2, 2], [2, 3], [2, 2], [4, 5], [0, 1], [0, 1]]
输出:
[null, true, false, true, true, true, false]

解释:
LockingTree lockingTree = new LockingTree([-1, 0, 0, 1, 1, 2, 2]);
lockingTree.lock(2, 2); // 返回 true ,因为节点 2 未上锁。
// 节点 2 被用户 2 上锁。
lockingTree.unlock(2, 3); // 返回 false ,因为用户 3 无法解锁被用户 2 上锁的节点。
lockingTree.unlock(2, 2); // 返回 true ,因为节点 2 之前被用户 2 上锁。
// 节点 2 现在变为未上锁状态。
lockingTree.lock(4, 5); // 返回 true ,因为节点 4 未上锁。
// 节点 4 被用户 5 上锁。
lockingTree.upgrade(0, 1); // 返回 true ,因为节点 0 未上锁且至少有一个被上锁的子孙节点(节点 4)。
// 节点 0 被用户 1 上锁,节点 4 变为未上锁。
lockingTree.lock(0, 1); // 返回 false ,因为节点 0 已经被上锁了。

提示
  • n == parent.length
  • 2 <= n <= 2000
  • 对于 i != 0 ,满足 0 <= parent[i] <= n - 1
  • parent[0] == -1
  • 0 <= num <= n - 1
  • 1 <= user <= 104
  • parent 表示一棵合法的树。
  • lockunlockupgrade 的调用 总共 不超过 2000 次。
做题历程

​ 这个题乍一看看不懂啥意思,但是你仔细看看,就会发现确实看不懂。最近做题老是看不懂题意,这就导致我最近写算发的第一道难关就是弄明白题目到底要我做什么。不夸张的说,这个题我前前后后看了有五六遍,才大致明白了他要我干什么,但是我还是没完全明白,遗漏了许多小细节,导致我之后在错误的道路上一路狂奔,不过还好没偏离大致方向。因为这道题错的实在是太多,自己给自己挖的坑也实在是不少,所以就想把这道题记录一下,也算是没白踩这么多坑。先说一下我在做这道题的时候遇到的坑。

  • 第一个就是在看完这道题之后,结合题目给出的案例,让我自以为这道题给出的parent数组都是跟示例一样,排列好的,这给了我第一个误差,让我以为知道了父结点就可以根据规律求出他的子节点。
  • 第二个就是我自以为题目中的树就是示例给出的二叉树,一个父结点只有两个子节点,但是题目上没有任何字眼说明这个树就是二叉树。当我意识道这个的时候我就知道,我的代码白写了。
做题思路

​ 虽然自己给自己挖的坑不少,单也是在对树的结构上的问题,整体大的方向还是对的,也就是我的思路没有太大的问题。

数组定义

​ 首先题目给出一个parent数组,里面记录了每一个节点的父结点是谁,根据这个数组,我们可以从一个节点向上搜寻,一直找到树的根节点,可以用来解决第三个方法锁升级的向上搜寻。

​ 然后就是题目要求要记录是谁给节点加的锁,这个需要额外开一个数组来记录每个节点的锁持有者信息,因为题目明确表明加锁的用户数据范围是1 <= user <= 104,所以锁数组不需要进行初始化,默认的0值就可以标识此节点目前没有用户加锁。

​ 以上都是我一开始的思路,都是正确的,关于子节点的搜寻的思路,我一开始的方向是错的,我一开始以为可以根据规律求出子节点,就没有开辟额外的数组空间来记录子节点,之后发现不行,就开辟了一个二维数组来存储子节点。但是每个父结点的子节点数量不是固定的,第二次关于子节点的思路又错了。然后我又改成ArrayList<ArrayList> 类型,但是由于这个时候我的脑子已经一团糊了,这个又比较麻烦,老有错误,之后就实在没办法了,翻了一下题解,有一个题解是这样定义子存储子节点的结构的,他使用了一个ArrayList[]类型,觉得很对,就按照这个定义了。

    private int[] parent;
    private ArrayList<Integer>[] children;
    private int[] locak;
    private int len;
    public LockingTree(int[] parent) {
        this.parent = parent;
        this.len = parent.length;
        locak = new int[len];
        this.children = new ArrayList[len];
        Arrays.setAll(children, i -> new ArrayList<>());
        for (int i = 1; i < len; i++) {
            children[parent[i]].add(i);
        }
    }
编写代码

locak方法:加锁方法比较简单,传入需要加锁的节点和加锁的用户,如果这个节点当前属于未加锁的状态,则,用户加锁成功,返回true,若当前节点已加锁,则加锁失败。

    public boolean lock(int num, int user) {
        if(locak[num] == 0){
            locak[num] = user;
            return true;
        }
        return false;
    }

unlocak方法:解锁方法也不复杂,传入需要解锁的节点,查看当前节点上锁的用户与解锁的用户是否为同一人,若是则解锁成功,不是则解锁失败。

    public boolean unlock(int num, int user) {
        if(locak[num] == user){
            locak[num] = 0;
            return true;
        }
        return false;
    }

upgrade方法:升级锁方法比较麻烦,需要满足三个条件,当前节点和父结点(一直到根节点为止)不能有加锁的节点,并且所有子节点中至少需要有一个加锁的节点。升级成功需要将当前节点变为加锁状态,将加锁的子节点解锁。

因为我的思路不对,所以我折腾了大半晌也没弄出来,看了一个使用了dfs的题解,我一开始的思路是使用队列一个一个遍历子节点,不过还是深度优先跟简便一些。

public boolean upgrade(int num, int user) {
        int x = num;
        while (x != -1) {
            if (locak[x] != 0) {
                return false;
            }
            x = parent[x];
        }
        boolean[] find = new boolean[1];
        dfs(num, find);
        if(find[0]){
            locak[num]=user;
        }
        return find[0];
    }
    void dfs(int num,boolean[] find){
        for(int a : children[num]){
            if(locak[a] != 0){
                locak[a] = 0;
                find[0] = true;
            }
            dfs(a,find);
        }
    }
}
完整代码
class LockingTree {
    private int[] parent;
    private ArrayList<Integer>[] children;
    private int[] locak;
    private int len;
    public LockingTree(int[] parent) {
        this.parent = parent;
        this.len = parent.length;
        locak = new int[len];
        this.children = new ArrayList[len];
        Arrays.setAll(children, i -> new ArrayList<>());
        for (int i = 1; i < len; i++) {
            children[parent[i]].add(i);
        }
    }

    public boolean lock(int num, int user) {
        if(locak[num] == 0){
            locak[num] = user;
            return true;
        }
        return false;
    }

    public boolean unlock(int num, int user) {
        if(locak[num] == user){
            locak[num] = 0;
            return true;
        }
        return false;
    }

    public boolean upgrade(int num, int user) {
        int x = num;
        while (x != -1) {
            if (locak[x] != 0) {
                return false;
            }
            x = parent[x];
        }
        boolean[] find = new boolean[1];
        dfs(num, find);
        if(find[0]){
            locak[num]=user;
        }
        return find[0];
    }
    void dfs(int num,boolean[] find){
        for(int a : children[num]){
            if(locak[a] != 0){
                locak[a] = 0;
                find[0] = true;
            }
            dfs(a,find);
        }
    }
}

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

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

相关文章

Java多线程篇(5)——cas和atomic原子类

文章目录 CASAtomic 原子类一般原子类针对aba问题 —— AtomicStampedReference针对大量自旋问题 —— LongAdder CAS 原理大致如下&#xff1a; 在java的 Unsafe 类里封装了一些 cas 的api。以 compareAndSetInt 为例&#xff0c;来看看其底层实现。 可以发现&#xff0c;最…

基于abaqus的非等速生长Voronoi晶体模型生成插件

1. 非等速生长晶体模型简介 对于标准Voronoi而言&#xff0c;每个晶粒的生长速率是相同的&#xff0c;任意两个晶粒的交界线为其形核点连线的垂直平分线&#xff0c;交界线为一条直线&#xff0c;如图1.1所示。 图1.1 标准Voronoi晶粒交界线 而对于非等速生长Voronoi晶体而言…

项目篇——java文档搜索引擎

Java 文档搜索引擎 文章目录 Java 文档搜索引擎一、分词二、完成parser 类2.1、排除非html文件2.2、解析html以下是解析 HTML 标题的方法以下是解析 对应的 URL以下是解析 HTML的正文&#xff1a; 补充&#xff1a;倒序索引 三、实现 index 类3.1、实现索引结构3.2、索引中新增…

学会使用Git 和 GitHub

Git 和 GitHub 都是程序员每天都要用到的东西 —— 前者是目前最先进的 版本控制工具&#xff0c;拥有最多的用户&#xff0c;且管理着地球上最庞大的代码仓库&#xff1b;而后者是全球最大 同性交友 代码托管平台、开源社区。 在没有这两个工具时&#xff0c;编程可能是这样的…

Go环境搭建

下载 官网地址 选择Download 根据自己的请选择对应的版本进行下载(我这里使用windos go.1.21.1版本) 我这里选择zip类型进行下载免安装版(你也可以选择mis类型进行下载,安装版一步一步next就行)。 安装 解压安装包 目录说明 配置环境变量 验证是否安装成功 完成上述配置…

通过插件去除Kotlin混淆去除 @Metadata标记

在Kotlin中&#xff0c;Metadata是指描述Kotlin类的元数据。它包含了关于类的属性、函数、注解和其他信息的描述。Metadata的作用主要有以下几个方面&#xff1a; 反射&#xff1a;Metadata可以用于在运行时获取类的信息&#xff0c;包括类的名称、属性、函数等。通过反射&…

【功能设计】数据分发功能设计

文章目录 设计脑图功能性非功能性 功能设计文档1. 需求分析1.1、功能性需求1.2、非功能性需求 2. 功能设计2.1 业务流程图2.2 数据流图2.3 表结构设计2.4 接口设计2.5 功能点 3.非功能性设计3.1 性能3.2 可用性3.3 并发性3.4 安全性 设计脑图 功能性 非功能性 功能设计文档 1…

国庆中秋特辑(三)使用生成对抗网络(GAN)生成具有节日氛围的画作,深度学习框架 TensorFlow 和 Keras 来实现

要用人工智能技术来庆祝国庆中秋&#xff0c;我们可以使用生成对抗网络&#xff08;GAN&#xff09;生成具有节日氛围的画作。这里将使用深度学习框架 TensorFlow 和 Keras 来实现。 一、生成对抗网络&#xff08;GAN&#xff09; 生成对抗网络&#xff08;GANs&#xff0c;…

FFMpeg zoompan 镜头聚焦和移动走位

案例 原始图片 # 输出帧数&#xff0c;默认25帧/秒&#xff0c;25*4 代表4秒 # s1280x80 # 输出视频比例&#xff0c;可以设置和输入图片大小一致 # zoom0.002 表示每帧放大的倍数&#xff0c;下面代码是25帧/每秒 * 4秒&#xff0c;共1000帧 # 最终是 0.002*25*4 0.2&…

什么是深度学习?最易懂的机器学习入门文章

1. 什么是深度学习? 深度学习是机器学习领域中一个新的研究方向&#xff0c;它被引入机器学习使其更接近于人工智能。 原文&#xff1a;【科普&实践】超详细&#xff01;一文带你玩转深度学习 - 飞桨AI Studio星河社区 深度学习是机器学习领域中一个新的研究方向&#xff…

折腾LINUX复古终端

这个复古终端是cool-retro-term&#xff0c;先来图 点击GITHUB地址 开始用docker运行&#xff0c;报错。后来用x11docker&#xff0c;因为我要远程通过SSH的x11转发&#xff0c;但实际x11docker的默认backbone就说docker&#xff0c;也就说要先用docker下载镜像&#xff0c…

[maven] 实现使用 plugin 及 properties 简述

[maven] 实现&使用 plugin 及 properties 简述 这章内容&#xff0c;我个人感觉可看可不看……&#xff1f; 不过课都上了&#xff0c;笔记 &#x1f4d2; 补完才对得起自己嘛 plugins 主要讲一下 maven 的 plugin 时怎么实现的&#xff0c;以及项目中怎么调用自己实现…

成集云 | 用友T+集成聚水潭ERP(用友T+主管供应链)| 解决方案

源系统成集云目标系统 方案介绍 用友T是一款由用友畅捷通推出的新型互联网企业管理系统&#xff0c;它主要满足成长型小微企业对其灵活业务流程的管控需求&#xff0c;并重点解决往来业务管理、订单跟踪、资金、库存等管理难题。 聚水潭是一款以SaaS ERP为核心&#xff0c;集…

mysql事务测试

mysql的事务处理主要有两种方法1、用begin,rollback,commit来实现 begin; -- 开始一个事务 rollback; -- 事务回滚 commit; -- 事务提交 2、直接用set来改变mysql的自动提交模式 mysql默认是自动提交的&#xff0c;也就是你提交一个sql&#xff0c;它就直接执行&#xff01;我…

微信管理系统可以解决什么问题?

微信作为一款社交通讯软件&#xff0c;已经成为人们日常生活中不可缺少的工具。不仅个人&#xff0c;很多企业都用微信来联系客户、维护客户和营销&#xff0c;这自然而然就会有很多微信账号、手机也多&#xff0c;那管理起来就会带来很多的不便&#xff0c;而微信管理系统正好…

基于径向基神经RBF的空调功率预测,RBF神经网络的详细原理,RBF回归预测代码

目录 完整代码和数据下载链接&#xff1a;基于MATLAB的RBF的空调能耗预测_模糊空调matlab资源-CSDN文库 https://download.csdn.net/download/abc991835105/87833598 RBF的详细原理 RBF的定义 RBF理论 易错及常见问题 RBF应用实例&#xff0c;基于rbf的空调功率预测 代码 结果…

C语言大佬的必杀技---宏的高级用法

C语言大佬的必杀技—宏的高级用法 目录: 字符串化标记的拼接宏的嵌套替换多条语句防止一个文件被重复包含宏和函数的区别 可能大家在学习的时候用得比较少&#xff0c;但是在一些代码量比较大的时候&#xff0c;这样使用&#xff0c;可以大大的提高代码的可读性&#xff0c;…

minio报错should be less than or equal解决方案

minio报错should be less than or equal解决方案 问题背景解决方案Lyric&#xff1a; 当作你的请求 问题背景 在进行minio扩容时&#xff0c;报错 parity validation returned an error: parity 4 should be less than or equal to 2 <- (4, 4), for pool(2nd解决方案 mi…

ModbusTCP 转 Profinet 主站网关控制汇川伺服驱动器配置案例

ModbusTCP Client 通过 ModbusTCP 控制 Profinet 接口设备&#xff0c;Profinet 接口设备接入 DCS/工控机等 兴达易控ModbusTCP转Profinet主站网关&#xff08;XD-ETHPNM20&#xff09;采用数据映射方式进行工作。 使用设备&#xff1a;兴达易控ModbusTCP 转 Profinet 主站网关…

敏捷开发七大步骤和敏捷工具

敏捷开发是一种以人为核心、迭代、循序渐进的开发方法。在敏捷开发中&#xff0c;软件项目的构建被切分成多个子项目&#xff0c;各个子项目的成果都经过测试&#xff0c;具备集成和可运行的特征。敏捷开发并不追求前期完美的设计、完美编码&#xff0c;而是力求在很短的周期内…