-
Notifications
You must be signed in to change notification settings - Fork 2.3k
/
1993-operations-on-tree.js
120 lines (113 loc) · 3.25 KB
/
1993-operations-on-tree.js
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
class LockingTree {
/**
* @param {number[]} parent
*/
constructor(parent) {
this.parent = parent;
this.childHash = {};
this.treeHash = {};
for(let i = 0; i < parent.length; i++) {
if(this.childHash[parent[i]]) {
this.childHash[parent[i]].push(i);
} else {
this.childHash[parent[i]] = [i];
}
}
}
/**
* Time O(1) | Space O(1)
* @param {number} num
* @param {number} user
* @return {boolean}
*/
lock(num, user) {
// it will just lock a node for a given user if it's not already locked THAT'S IT!
if(this.treeHash[num]) return false;
this.treeHash[num] = user;
return true;
}
/**
* Time O(1) | Space O(1)
* @param {number} num
* @param {number} user
* @return {boolean}
*/
unlock(num, user) {
// only unlock the node if it's locked by the same user
if(this.treeHash[num] === user) {
delete this.treeHash[num];
return true;
}
return false;
}
/**
*
* Time O(n) | Space O(n)
* @param {number} num
* @param {number} user
* @return {boolean}
*/
upgrade(num, user) {
// lock the node for a given user and unlock all of its descendants no matter who locked it.
// 1. the given node should be unlocked
// 2. the given node should have at least one locked node descendant by anyone
// 3. the given node shouldn't have any locked ancestors
if(this.treeHash[num]) return false;
if(!this.checkDescendants(num)) return false;
if(!this.checkAncestors(num)) return false;
// locking the given node
this.treeHash[num] = user;
this.unlockDescendants(num);
return true;
}
/**
* Helper method to unlock descendants
* Time O(n) | Space O(n)
* @param {number} index
*/
unlockDescendants(index) {
const stack = [];
stack.push(index);
while(stack.length) {
const node = stack.pop();
const children = this.childHash[node];
for(let i = 0; i < (children && children.length); i++) {
delete this.treeHash[children[i]];
stack.push(children[i]);
}
}
}
/**
* Helper method to check ancestors
* Time O(n) | Space O(1)
* @param {number} index
* @return {boolean}
*/
checkAncestors(index) {
let node = this.parent[index];
while(node !== -1) {
if(this.treeHash[node]) return false;
node = this.parent[node];
}
return true;
}
/**
* Helper method to check descendants
* Time O(n) | Space O(n)
* @param {number} index
* @return {boolean}
*/
checkDescendants(index) {
const stack = [];
stack.push(index);
while(stack.length) {
const node = stack.pop();
const children = this.childHash[node];
for(let i = 0; i < (children && children.length); i++) {
if(this.treeHash[children[i]]) return true;
stack.push(children[i]);
}
}
return false;
}
}