{x}
blog image

Clone Binary Tree With Random Pointer

Solution Explanation

This problem requires creating a deep copy of a binary tree where each node has an additional random pointer that can point to any node in the tree or be null. The solution uses Depth-First Search (DFS) and a hash map (dictionary in Python) to efficiently track nodes and their corresponding copies.

Approach

The core idea is to perform a recursive DFS traversal of the tree. For each node encountered:

  1. Check the hash map: If the node already exists in the hash map (meaning its copy has already been created), return the copied node.

  2. Create a new node: Otherwise, create a new node (NodeCopy) with the same value as the original node.

  3. Store in hash map: Add the original node and its newly created copy to the hash map to avoid redundant work.

  4. Recursively copy children and random pointer: Recursively call the dfs function on the left and right children of the current node and on the node pointed to by the random pointer. This ensures a deep copy where all connections are replicated.

  5. Return the copied node: Return the newly created copied node.

Time and Space Complexity Analysis

  • Time Complexity: O(N), where N is the number of nodes in the tree. This is because each node is visited and processed exactly once during the DFS traversal.

  • Space Complexity: O(N) in the worst case. This is due to the space used by the hash map to store the mapping between original nodes and their copied counterparts. In the worst-case scenario (a skewed tree), the recursion depth can also be O(N).

Code Explanation (Python)

class Solution:
    def copyRandomBinaryTree(self, root: 'Optional[Node]') -> 'Optional[NodeCopy]':
        def dfs(root):
            if root is None:
                return None
            if root in mp:
                return mp[root]  # If already copied, return the copy
            copy = NodeCopy(root.val)
            mp[root] = copy     # Store the mapping
            copy.left = dfs(root.left)
            copy.right = dfs(root.right)
            copy.random = dfs(root.random)
            return copy
 
        mp = {}  # Hash map to store node mappings
        return dfs(root)

The code in other languages (Java, C++, Go) follows the same logic, utilizing their respective hash map implementations (HashMap, unordered_map, map). The key difference lies primarily in the syntax and data structures used, but the algorithmic core remains identical. The use of a hash map ensures that we avoid repeatedly copying the same nodes, leading to the optimal O(N) time complexity.