概述
给你一棵 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 次。
解题思路
使用map维护被锁节点和加锁者的关系,再使用一个map维护父节点和对应子节点之间的关系
lock
判断是否有锁,如果没有,则可以直接加锁
unlock
判断当前锁的加锁者是否为自己
upgrade
- 先向上遍历祖先节点和加锁节点,判断是否有加锁
- 再遍历子孙节点,判断是否加锁
- 给所有子孙节点解锁,给当前节点加锁
代码
class LockingTree {
int[] p;
Map<Integer, Integer> locked = new HashMap<>();
Map<Integer,Set<Integer>> child=new HashMap<>();
public LockingTree(int[] parent) {
p = parent;
for (int i = 0; i < parent.length; i++) {
if (!child.containsKey(p[i]))
child.put(p[i],new HashSet<>());
child.get(p[i]).add(i);
}
}
public boolean lock(int num, int user) {
if (locked.containsKey(num) )
return false;
locked.put(num, user);
return true;
}
public boolean unlock(int num, int user) {
if (locked.containsKey(num) && locked.get(num) == user) {
locked.remove(num);
return true;
} else return false;
}
public boolean dfs(int num) {
while (num!=-1)
{
if(locked.containsKey(num))
return false;
num=p[num];
}
return true;
}
public boolean ddfs(int num,int f) {
if (locked.containsKey(num)&&num!=f){
return true;
}
boolean res=false;
if (child.containsKey(num))
{
for (Integer integer : child.get(num)) {
res|=ddfs(integer,f);
}
}
return res;
}
public void dddfs(int num) {
locked.remove(num);
if (child.containsKey(num))
{
for (Integer integer : child.get(num)) {
dddfs(integer);
}
}
}
public boolean upgrade(int num, int user) {
if (dfs(num)&&ddfs(num,num))
{
dddfs(num);
locked.put(num, user);
return true;
}
return false;
}
}
/**
* Your LockingTree object will be instantiated and called as such:
* LockingTree obj = new LockingTree(parent);
* boolean param_1 = obj.lock(num,user);
* boolean param_2 = obj.unlock(num,user);
* boolean param_3 = obj.upgrade(num,user);
*/
/**
* Your LockingTree object will be instantiated and called as such:
* LockingTree obj = new LockingTree(parent);
* boolean param_1 = obj.lock(num,user);
* boolean param_2 = obj.unlock(num,user);
* boolean param_3 = obj.upgrade(num,user);
*/
最后
以上就是称心毛巾为你收集整理的5848. 树上的操作的全部内容,希望文章能够帮你解决5848. 树上的操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复