Skip to content

Add solution and test-cases for problem 1993 #917

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 37 additions & 16 deletions leetcode/1901-2000/1993.Operations-on-Tree/README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,49 @@
# [1993.Operations on Tree][title]

> [!WARNING|style:flat]
> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm)

## Description
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.

**Example 1:**
The data structure should support the following functions:

```
Input: a = "11", b = "1"
Output: "100"
```
- **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.
- **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.
- **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:

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

## 题解
Implement the `LockingTree` class:

### 思路1
> ...
Operations on Tree
```go
```
- `LockingTree(int[] parent)` initializes the data structure with the parent array.
- `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`.
- `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**.
- `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**.

**Example 1:**

![1](./untitled.png)

```
Input
["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]]
Output
[null, true, false, true, true, true, false]

Explanation
LockingTree lockingTree = new LockingTree([-1, 0, 0, 1, 1, 2, 2]);
lockingTree.lock(2, 2); // return true because node 2 is unlocked.
// Node 2 will now be locked by user 2.
lockingTree.unlock(2, 3); // return false because user 3 cannot unlock a node locked by user 2.
lockingTree.unlock(2, 2); // return true because node 2 was previously locked by user 2.
// Node 2 will now be unlocked.
lockingTree.lock(4, 5); // return true because node 4 is unlocked.
// Node 4 will now be locked by user 5.
lockingTree.upgrade(0, 1); // return true because node 0 is unlocked and has at least one locked descendant (node 4).
// Node 0 will now be locked by user 1 and node 4 will now be unlocked.
lockingTree.lock(0, 1); // return false because node 0 is already locked.
```

## 结语

Expand Down
101 changes: 99 additions & 2 deletions leetcode/1901-2000/1993.Operations-on-Tree/Solution.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,102 @@
package Solution

func Solution(x bool) bool {
return x
type LockingTree struct {
tree []int
locker []int
children map[int][]int
}

func Constructor(parent []int) LockingTree {
children := make(map[int][]int)
for c, p := range parent {
if _, ok := children[p]; !ok {
children[p] = make([]int, 0)
}
children[p] = append(children[p], c)
}
return LockingTree{tree: parent, locker: make([]int, len(parent)), children: children}
}

// u, u, ul, l, u
func (this *LockingTree) Lock(num int, user int) bool {
if this.locker[num] != 0 {
return false
}
this.locker[num] = user
return true
}

func (this *LockingTree) Unlock(num int, user int) bool {
if this.locker[num] == 0 || this.locker[num] != user {
return false
}
this.locker[num] = 0
return true
}

func (this *LockingTree) ancesors(num int) bool {
for {
if num == -1 {
return false
}
if this.locker[num] != 0 {
return true
}
num = this.tree[num]
}
}

func (this *LockingTree) unlockDescendant(num int) bool {
q := []int{num}
found := false
for len(q) > 0 {
nq := make([]int, 0)
for _, i := range q {
if this.locker[i] != 0 {
this.locker[i] = 0
found = true
}
for _, c := range this.children[i] {
nq = append(nq, c)
}
}
q = nq
}
return found
}

func (this *LockingTree) Upgrade(num int, user int) bool {
if this.locker[num] != 0 {
return false
}
if this.ancesors(num) {
return false
}
if !this.unlockDescendant(num) {
return false
}
this.locker[num] = user
return true
}

type op struct {
name string
a, b int
}

func Solution(p []int, opts []op) []bool {
c := Constructor(p)
ans := make([]bool, 0)
for _, o := range opts {
if o.name == "l" {
ans = append(ans, c.Lock(o.a, o.b))
continue
}
if o.name == "u" {
ans = append(ans, c.Unlock(o.a, o.b))
continue
}
ans = append(ans, c.Upgrade(o.a, o.b))
}
return ans
}
26 changes: 16 additions & 10 deletions leetcode/1901-2000/1993.Operations-on-Tree/Solution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,36 @@ func TestSolution(t *testing.T) {
// 测试用例
cases := []struct {
name string
inputs bool
expect bool
p []int
opts []op
expect []bool
}{
{"TestCase", true, true},
{"TestCase", true, true},
{"TestCase", false, false},
{"TestCase1", []int{-1, 0, 0, 1, 1, 2, 2}, []op{
{"l", 2, 2},
{"u", 2, 3},
{"u", 2, 2},
{"l", 4, 5},
{"", 0, 1},
{"l", 0, 1},
}, []bool{true, false, true, true, true, false}},
}

// 开始测试
for i, c := range cases {
t.Run(c.name+" "+strconv.Itoa(i), func(t *testing.T) {
got := Solution(c.inputs)
got := Solution(c.p, c.opts)
if !reflect.DeepEqual(got, c.expect) {
t.Fatalf("expected: %v, but got: %v, with inputs: %v",
c.expect, got, c.inputs)
t.Fatalf("expected: %v, but got: %v, with inputs: %v %v",
c.expect, got, c.p, c.opts)
}
})
}
}

// 压力测试
// 压力测试
func BenchmarkSolution(b *testing.B) {
}

// 使用案列
// 使用案列
func ExampleSolution() {
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading