#1993
Operations on Tree
MediumArrayHash TableTreeDepth-First SearchBreadth-First SearchDesignHash MapArray
Approaches
Brute ForceOptimal
Complexity Comparison
| Brute Force | Optimal Solution★ | |
|---|---|---|
| Time | O(n²) | O(n) |
| Space | O(1) | O(n) |
💡
Intuition
Time O(n)Space O(n)
This approach efficiently manages the locking and unlocking operations by using a combination of a parent-child relationship and a map to track locked nodes. It allows us to quickly check conditions for locking, unlocking, and upgrading without redundant traversals.
⚙️
Algorithm
4 steps- 1Step 1: Store the parent-child relationships in a list and maintain a map for locked nodes.
- 2Step 2: For locking, check if the node is unlocked and lock it for the user.
- 3Step 3: For unlocking, check if the node is locked by the same user and unlock it.
- 4Step 4: For upgrading, check the three conditions (unlocked, has locked descendant, no locked ancestor) and perform the operations accordingly.
solution.py51 lines
1class LockingTree:
2 def __init__(self, parent):
3 self.parent = parent
4 self.locked = {}
5 self.children = [[] for _ in range(len(parent))]
6 for i in range(1, len(parent)):
7 self.children[parent[i]].append(i)
8
9 def lock(self, num, user):
10 if num in self.locked:
11 return False
12 self.locked[num] = user
13 return True
14
15 def unlock(self, num, user):
16 if num not in self.locked or self.locked[num] != user:
17 return False
18 del self.locked[num]
19 return True
20
21 def upgrade(self, num, user):
22 if num in self.locked:
23 return False
24 if not self.has_locked_descendant(num):
25 return False
26 if self.has_locked_ancestor(num):
27 return False
28 self.locked[num] = user
29 self.unlock_descendants(num)
30 return True
31
32 def has_locked_descendant(self, num):
33 if num in self.locked:
34 return True
35 for child in self.children[num]:
36 if self.has_locked_descendant(child):
37 return True
38 return False
39
40 def has_locked_ancestor(self, num):
41 while num != -1:
42 if num in self.locked:
43 return True
44 num = self.parent[num]
45 return False
46
47 def unlock_descendants(self, num):
48 if num in self.locked:
49 del self.locked[num]
50 for child in self.children[num]:
51 self.unlock_descendants(child)ℹ
Complexity note: This complexity is due to the fact that we can efficiently check for locked nodes and their relationships using a map and a list, allowing us to avoid redundant traversals.
- 1Understanding tree traversal is crucial for managing parent-child relationships.
- 2Efficiently tracking locked nodes can significantly reduce operation time.
Solutions and explanations are original Tejav content. Problem titles © LeetCode — use the LeetCode button above for the full problem statement.