Skip to content

Commit 5155e28

Browse files
authored
Merge pull request #917 from 0xff-dev/1993
Add solution and test-cases for problem 1993
2 parents 5d8444d + 68355cf commit 5155e28

File tree

4 files changed

+152
-28
lines changed

4 files changed

+152
-28
lines changed

leetcode/1901-2000/1993.Operations-on-Tree/README.md

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,49 @@
11
# [1993.Operations on Tree][title]
22

3-
> [!WARNING|style:flat]
4-
> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm)
5-
63
## Description
4+
You are given a tree with `n` nodes numbered from `0` to `n - 1` in the form of a parent array `parent` where `parent[i]` is the parent of the i<sup>th</sup> node. The root of the tree is node `0`, so `parent[0] = -1` since it has no parent. You want to design a data structure that allows users to lock, unlock, and upgrade nodes in the tree.
75

8-
**Example 1:**
6+
The data structure should support the following functions:
97

10-
```
11-
Input: a = "11", b = "1"
12-
Output: "100"
13-
```
8+
- **Lock: Locks** the given node for the given user and prevents other users from locking the same node. You may only lock a node using this function if the node is unlocked.
9+
- **Unlock: Unlocks** the given node for the given user. You may only unlock a node using this function if it is currently locked by the same user.
10+
- **Upgrade: Locks** the given node for the given user and **unlocks** all of its descendants **regardless** of who locked it. You may only upgrade a node if **all** 3 conditions are true:
1411

15-
## 题意
16-
> ...
12+
- The node is unlocked,
13+
- It has at least one locked descendant (by any user), and
14+
- It does not have any locked ancestors.
1715

18-
## 题解
16+
Implement the `LockingTree` class:
1917

20-
### 思路1
21-
> ...
22-
Operations on Tree
23-
```go
24-
```
18+
- `LockingTree(int[] parent)` initializes the data structure with the parent array.
19+
- `lock(int num, int user)` returns `true` if it is possible for the `user` with id user to lock the node `num`, or false otherwise. If it is possible, the node `num` will become **locked** by the user with id `user`.
20+
- `unlock(int num, int user)` returns `true` if it is possible for the `user` with id user to unlock the node `num`, or `false` otherwise. If it is possible, the node `num` will become **unlocked**.
21+
- `upgrade(int num, int user)` returns `true` if it is possible for the `user` with id user to upgrade the node `num`, or `false` otherwise. If it is possible, the node `num` will be **upgraded**.
2522

23+
**Example 1:**
24+
25+
![1](./untitled.png)
26+
27+
```
28+
Input
29+
["LockingTree", "lock", "unlock", "unlock", "lock", "upgrade", "lock"]
30+
[[[-1, 0, 0, 1, 1, 2, 2]], [2, 2], [2, 3], [2, 2], [4, 5], [0, 1], [0, 1]]
31+
Output
32+
[null, true, false, true, true, true, false]
33+
34+
Explanation
35+
LockingTree lockingTree = new LockingTree([-1, 0, 0, 1, 1, 2, 2]);
36+
lockingTree.lock(2, 2); // return true because node 2 is unlocked.
37+
// Node 2 will now be locked by user 2.
38+
lockingTree.unlock(2, 3); // return false because user 3 cannot unlock a node locked by user 2.
39+
lockingTree.unlock(2, 2); // return true because node 2 was previously locked by user 2.
40+
// Node 2 will now be unlocked.
41+
lockingTree.lock(4, 5); // return true because node 4 is unlocked.
42+
// Node 4 will now be locked by user 5.
43+
lockingTree.upgrade(0, 1); // return true because node 0 is unlocked and has at least one locked descendant (node 4).
44+
// Node 0 will now be locked by user 1 and node 4 will now be unlocked.
45+
lockingTree.lock(0, 1); // return false because node 0 is already locked.
46+
```
2647

2748
## 结语
2849

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,102 @@
11
package Solution
22

3-
func Solution(x bool) bool {
4-
return x
3+
type LockingTree struct {
4+
tree []int
5+
locker []int
6+
children map[int][]int
7+
}
8+
9+
func Constructor(parent []int) LockingTree {
10+
children := make(map[int][]int)
11+
for c, p := range parent {
12+
if _, ok := children[p]; !ok {
13+
children[p] = make([]int, 0)
14+
}
15+
children[p] = append(children[p], c)
16+
}
17+
return LockingTree{tree: parent, locker: make([]int, len(parent)), children: children}
18+
}
19+
20+
// u, u, ul, l, u
21+
func (this *LockingTree) Lock(num int, user int) bool {
22+
if this.locker[num] != 0 {
23+
return false
24+
}
25+
this.locker[num] = user
26+
return true
27+
}
28+
29+
func (this *LockingTree) Unlock(num int, user int) bool {
30+
if this.locker[num] == 0 || this.locker[num] != user {
31+
return false
32+
}
33+
this.locker[num] = 0
34+
return true
35+
}
36+
37+
func (this *LockingTree) ancesors(num int) bool {
38+
for {
39+
if num == -1 {
40+
return false
41+
}
42+
if this.locker[num] != 0 {
43+
return true
44+
}
45+
num = this.tree[num]
46+
}
47+
}
48+
49+
func (this *LockingTree) unlockDescendant(num int) bool {
50+
q := []int{num}
51+
found := false
52+
for len(q) > 0 {
53+
nq := make([]int, 0)
54+
for _, i := range q {
55+
if this.locker[i] != 0 {
56+
this.locker[i] = 0
57+
found = true
58+
}
59+
for _, c := range this.children[i] {
60+
nq = append(nq, c)
61+
}
62+
}
63+
q = nq
64+
}
65+
return found
66+
}
67+
68+
func (this *LockingTree) Upgrade(num int, user int) bool {
69+
if this.locker[num] != 0 {
70+
return false
71+
}
72+
if this.ancesors(num) {
73+
return false
74+
}
75+
if !this.unlockDescendant(num) {
76+
return false
77+
}
78+
this.locker[num] = user
79+
return true
80+
}
81+
82+
type op struct {
83+
name string
84+
a, b int
85+
}
86+
87+
func Solution(p []int, opts []op) []bool {
88+
c := Constructor(p)
89+
ans := make([]bool, 0)
90+
for _, o := range opts {
91+
if o.name == "l" {
92+
ans = append(ans, c.Lock(o.a, o.b))
93+
continue
94+
}
95+
if o.name == "u" {
96+
ans = append(ans, c.Unlock(o.a, o.b))
97+
continue
98+
}
99+
ans = append(ans, c.Upgrade(o.a, o.b))
100+
}
101+
return ans
5102
}

leetcode/1901-2000/1993.Operations-on-Tree/Solution_test.go

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,30 +10,36 @@ func TestSolution(t *testing.T) {
1010
// 测试用例
1111
cases := []struct {
1212
name string
13-
inputs bool
14-
expect bool
13+
p []int
14+
opts []op
15+
expect []bool
1516
}{
16-
{"TestCase", true, true},
17-
{"TestCase", true, true},
18-
{"TestCase", false, false},
17+
{"TestCase1", []int{-1, 0, 0, 1, 1, 2, 2}, []op{
18+
{"l", 2, 2},
19+
{"u", 2, 3},
20+
{"u", 2, 2},
21+
{"l", 4, 5},
22+
{"", 0, 1},
23+
{"l", 0, 1},
24+
}, []bool{true, false, true, true, true, false}},
1925
}
2026

2127
// 开始测试
2228
for i, c := range cases {
2329
t.Run(c.name+" "+strconv.Itoa(i), func(t *testing.T) {
24-
got := Solution(c.inputs)
30+
got := Solution(c.p, c.opts)
2531
if !reflect.DeepEqual(got, c.expect) {
26-
t.Fatalf("expected: %v, but got: %v, with inputs: %v",
27-
c.expect, got, c.inputs)
32+
t.Fatalf("expected: %v, but got: %v, with inputs: %v %v",
33+
c.expect, got, c.p, c.opts)
2834
}
2935
})
3036
}
3137
}
3238

33-
// 压力测试
39+
// 压力测试
3440
func BenchmarkSolution(b *testing.B) {
3541
}
3642

37-
// 使用案列
43+
// 使用案列
3844
func ExampleSolution() {
3945
}
Loading

0 commit comments

Comments
 (0)