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) {
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) {
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) {
if (this.treeHash[num]) return false;
if (!this.checkDescendants(num)) return false;
if (!this.checkAncestors(num)) return false;
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;
}
}