【C++图论】1993. 树上的操作|1861

devtools/2024/12/22 18:25:25/

本文涉及知识点

C++图论

LeetCode 1993. 上的操作

给你一棵 n 个节点的,编号从 0 到 n - 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 会被 升级

示例 1:

输入:
[“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 表示一棵合法的
lock ,unlock 和 upgrade 的调用 总共 不超过 2000 次。

图论

时间复杂度:O(nm) m是调用次数。
m_lock[cur] = user, 表示cur节点被user锁,user为-1,表示没有被锁。
m_vGrandParent[cur] 记录cur所有祖先。初始化方法:循环直到没有父节点。
m_vChilds[cur] 记录cur所有后代,后序DFS。也可直接将cur加到他的祖先中。

代码

核心代码

class LockingTree {public:LockingTree(vector<int>& parent) {const int N = parent.size();m_lock.assign(N, -1);m_vGrand.resize(N);m_vChilds.resize(N);for (int i = 0; i < N; i++) {int par = parent[i];while (-1 != par) {m_vGrand[i].emplace_back(par);m_vChilds[par].emplace_back(i);par = parent[par];}}}bool lock(int num, int user) {if (-1 != m_lock[num]) { return false; }m_lock[num] = user;return true;}bool unlock(int num, int user) {if (user != m_lock[num]) { return false; }m_lock[num] = -1;return true;}bool upgrade(int node, int user) {				int lockCnt = 0;for (const auto& i : m_vChilds[node]) {lockCnt += (-1 != m_lock[i]);}if (0 == lockCnt) { return false; }int lock2 = 0;for (const auto& i : m_vGrand[node]) {lock2 += (-1 != m_lock[i]);}if (lock2 > 0) { return false; }if (!lock(node, user)) { return false; }for (const auto& i : m_vChilds[node]) {m_lock[i] = -1;}return true;}vector<int> m_lock;vector<vector<int>> m_vGrand, m_vChilds;};

单元测试

	vector<int> source, target;vector<vector<int>> allowedSwaps;TEST_METHOD(TestMethod11){LockingTree lockingTree(vector<int>{ -1, 0, 0, 1, 1, 2, 2 });auto res =lockingTree.lock(2, 2);    // 返回 true ,因为节点 2 未上锁// 节点 2 被用户 2 上锁AssertEx(true, res);res = lockingTree.unlock(2, 3);  // 返回 false ,因为用户 3 无法解锁被用户 2 上锁的节点。AssertEx(false, res);res = lockingTree.unlock(2, 2);  // 返回 true ,因为节点 2 之前被用户 2 上锁// 节点 2 现在变为未上锁状态。AssertEx(true, res);res = lockingTree.lock(4, 5);    // 返回 true ,因为节点 4 未上锁// 节点 4 被用户 5 上锁AssertEx(true, res);res = lockingTree.upgrade(0, 1); // 返回 true ,因为节点 0 未上锁且至少有一个被上锁的子孙节点(节点 4)。// 节点 0 被用户 1 上锁,节点 4 变为未上锁AssertEx(true, res);res = lockingTree.lock(0, 1);    // 返回 false ,因为节点 0 已经被上锁了。AssertEx(false, res);}TEST_METHOD(TestMethod12){LockingTree lockingTree(vector<int>{ -1, 0, 3, 1, 0 });auto res = lockingTree.upgrade(4, 5);AssertEx(false, res);res = lockingTree.upgrade(3, 8);AssertEx(false, res);res = lockingTree.unlock(0, 7);AssertEx(false, res);res = lockingTree.lock(2, 7);AssertEx(true, res);res = lockingTree.upgrade(4,6);AssertEx(false, res);}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。


http://www.ppmy.cn/devtools/144443.html

相关文章

Zabbix6.0升级为6.4

为了体验一些新的功能&#xff0c;比如 Webhook 和问题抑制等&#xff0c;升级个小版本。 一、环境信息 1. 版本要求 一定要事先查看官方文档&#xff0c;确认组件要求的版本&#xff0c;否则版本过高或者过低都会出现问题。 2. 升级前后信息 环境升级前升级后操作系统CentOS…

【Git从入门到精通】——新版IDea集成Git、Idea集成Github、Gitee以及GItLab应用(看这一篇就够了)

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

操作系统(20)文件共享

前言 操作系统文件共享是指在不同设备或用户之间共享文件的功能&#xff0c;它使得多个用户或设备能够方便地访问、编辑和共享文件。 一、文件共享的作用 提高协作效率&#xff1a;文件共享允许团队成员之间方便地共享和编辑文件&#xff0c;从而提高协作效率。节省存储空间&am…

项目23:简易网络爬虫 --- 《跟着小王学Python·新手》

项目23&#xff1a;简易网络爬虫 — 《跟着小王学Python新手》 《跟着小王学Python》 是一套精心设计的Python学习教程&#xff0c;适合各个层次的学习者。本教程从基础语法入手&#xff0c;逐步深入到高级应用&#xff0c;以实例驱动的方式&#xff0c;帮助学习者逐步掌握Pyth…

macos控制台安装

terminal安装homebrew&#xff1a; /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"homebrew安装docker&#xff1a; brew install docker打开docker执行&#xff1a; open /Applications/Docker.app

[Unity Shader]【图形渲染】【游戏开发】 Unity Shader与原始Shader的区别

在Unity中,Shader是用于控制如何渲染图形的程序,通常涉及到对图形管线的自定义操作。尽管所有的着色器都遵循基本的图形渲染流程,但Unity Shader和原始Shader(通常指OpenGL/DirectX等底层API的Shader)之间存在显著差异。理解这些区别能帮助开发者更好地在Unity环境下进行图…

Leetcode Hot 100 【二叉树】104. 二叉树的最大深度

104. 二叉树的最大深度 已解答 简单 相关标签 相关企业 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3…

IP6822为智能手机提供无线充电方案的无线充电发射微控制SOC芯片

在无线充电技术日新月异的今天&#xff0c;一款能够引领潮流、满足多元化需求的芯片显得尤为重要。英集芯IP6822是一款专为智能手机、智能手表、无线耳机提供无线充电方案的无线充电发射微控制SOC芯片&#xff0c;集成了多种关键无线充电技术&#xff0c;包括H桥驱动模块、ASK通…