给你一棵 n 个节点的树,编号从 0 到 n - 1 ,以父节点数组 parent 的形式给出,其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点,所以 parent[0] = -1 ,因为它没有父节点。你想要设计一个数据结构实现树里面对节点的加锁,解锁和升级操作。
数据结构需要支持如下函数:
- Lock:指定用户给指定节点 上锁 ,上锁后其他用户将无法给同一节点上锁。只有当节点处于未上锁的状态下,才能进行上锁操作。
- Unlock:指定用户给指定节点 解锁 ,只有当指定节点当前正被指定用户锁住时,才能执行该解锁操作。
- Upgrade:指定用户给指定节点 上锁 ,并且将该节点的所有子孙节点 解锁 。只有如下 3 个条件 全部 满足时才能执行升级操作:
- 指定节点当前状态为未上锁。
- 指定节点至少有一个上锁状态的子孙节点(可以是 任意 用户上锁的)。
- 指定节点没有任何上锁的祖先节点。
请你实现 LockingTree 类:
复制代码
1
2
3
4
5LockingTree(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:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20输入: ["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
- 先向上遍历祖先节点和加锁节点,判断是否有加锁
- 再遍历子孙节点,判断是否加锁
- 给所有子孙节点解锁,给当前节点加锁
代码
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90class 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.内容请搜索靠谱客的其他文章。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复