Advertisement

Operations on Tree - LeetCode 1993 Solution

Operations on Tree - Complete Solution Guide

Operations on Tree is LeetCode problem 1993, a Medium level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.

Problem Statement

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 th 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. The data structure should support the following functions: Lock: Locks the given node for the given user and prevents other users from locking the same node. You may only lock a n

Detailed Explanation

The problem requires you to design a data structure, `LockingTree`, representing a tree with lock/unlock capabilities for individual nodes by different users. The tree is provided as a parent array, where `parent[i]` is the parent of node `i`, and node 0 is the root (parent[0] = -1). The data structure must support three operations: `lock(num, user)`, `unlock(num, user)`, and `upgrade(num, user)`. The `lock` operation allows a user to lock an unlocked node. The `unlock` operation allows a user to unlock a node they have previously locked. The `upgrade` operation is more complex: it locks a node for a given user, but only if the node is currently unlocked, it has at least one locked descendant (locked by any user), and none of its ancestors are locked. If the upgrade is successful, it also unlocks all the descendants of the upgraded node, regardless of who locked them.

Solution Approach

The solution implements the `LockingTree` class with the required methods. It uses an array `parent` to store the parent-child relationship, an array `locked` to store the user who has locked each node (0 if unlocked), and an adjacency list `children` to easily find the children of each node. `lock` and `unlock` simply check and update the `locked` array. The `upgrade` method first checks if the node is unlocked and if none of its ancestors are locked. Then, it uses Breadth-First Search (BFS) to determine if the node has any locked descendants. If all conditions are met, it locks the node, and then uses BFS again to unlock all its descendants.

Step-by-Step Algorithm

  1. Step 1: **Initialization (`__init__` / Constructor):** Store the `parent` array, initialize the `locked` array to 0 (unlocked), and create the `children` adjacency list to represent the tree's structure. Traverse parent array and for each node `i` that is not the root, add `i` to the children of parent[i].
  2. Step 2: **Lock (`lock`):** Check if the node `num` is currently unlocked (`locked[num] == 0`). If it is, lock it by setting `locked[num] = user` and return `True`. Otherwise, return `False`.
  3. Step 3: **Unlock (`unlock`):** Check if the node `num` is locked by the given user (`locked[num] == user`). If it is, unlock it by setting `locked[num] = 0` and return `True`. Otherwise, return `False`.
  4. Step 4: **Upgrade (`upgrade`):** a. Check if the node `num` is locked; if so, return `False`. b. Check if any ancestor of node `num` is locked; if so, return `False`. Traverse upwards from `num` to the root by following parent links. Return false if any ancestor is locked. c. Check if node `num` has at least one locked descendant. BFS is used to traverse descendants. Return false if no locked descendant found. d. If all the above conditions are met, lock node `num` for the given user, and unlock all descendants of node `num`. Another BFS is used. e. Return `True` if upgrade was successful.

Key Insights

  • Insight 1: Representing the tree using adjacency lists (children) is efficient for finding descendants in the upgrade operation.
  • Insight 2: Maintaining a 'locked' array to track the user who locked a node allows for constant-time lock/unlock checks.
  • Insight 3: The upgrade operation's constraints require carefully checking ancestors and descendants, so a clean implementation is vital to avoid errors.
  • Insight 4: Using BFS to traverse descendants for both checking for locked nodes during `upgrade` and unlocking them after upgrading is efficient.

Complexity Analysis

Time Complexity: O(n)

Space Complexity: O(n)

Topics

This problem involves: Array, Hash Table, Tree, Depth-First Search, Breadth-First Search, Design.

Companies

Asked at: Juspay.