Given the root of a binary tree where each node contains an additional pointer called random
that can point to any node in the tree or be null
, your task is to clone the entire tree. The cloned tree should have the same structure, values, and random pointer connections as the original, but must be composed entirely of newly created nodes (i.e., do not reuse any existing nodes from the input tree).
You are guaranteed that there is only one valid solution, and you must not modify the original tree or reuse its nodes. The function signature typically looks like:
class Node { int val; Node left; Node right; Node random; } Node copyRandomBinaryTree(Node root)
At first glance, cloning a binary tree is straightforward: traverse the tree and copy each node and its left/right pointers. However, the random
pointer introduces complexity, as it can point to any node in the tree (not just children or parents), or be null
.
A brute-force approach might attempt to clone the tree structure first, then for each node, search for the corresponding random
target in the cloned tree by value. But this is inefficient, especially if values are duplicated or the tree is large.
To optimize, we need a way to quickly find the cloned counterpart of any original node. This suggests mapping each original node to its clone as we traverse the tree—much like how we handle the "Copy List with Random Pointer" problem for linked lists.
The optimal solution uses a hash map (dictionary) to map each original node to its corresponding newly created clone node. Here’s the step-by-step approach:
left
and right
children, setting the pointers in the clone.random
pointer, using the map to avoid duplicating nodes and to handle cycles.random
pointers.
This approach ensures that each node is cloned exactly once, and all pointers (including random
) are set correctly in a single pass.
Example:
Consider a tree:
1 / \ 2 3Suppose:
random
points to Node 3random
points to Node 1random
is null
map[Node1] = Node1'
.
map[Node2] = Node2'
.
random
points to Node 1. The map already contains Node1'
, so set Node2'.random = Node1'
.
map[Node3] = Node3'
.
random
is null
, so Node3'.random = null
.
random
points to Node 3, so Node1'.random = Node3'
.
# Definition for a Node.
class Node:
def __init__(self, val=0, left=None, right=None, random=None):
self.val = val
self.left = left
self.right = right
self.random = random
class Solution:
def copyRandomBinaryTree(self, root: 'Node') -> 'Node':
old_to_new = {}
def clone(node):
if not node:
return None
if node in old_to_new:
return old_to_new[node]
copy = Node(node.val)
old_to_new[node] = copy
copy.left = clone(node.left)
copy.right = clone(node.right)
copy.random = clone(node.random)
return copy
return clone(root)
// Definition for a Node.
class Node {
public:
int val;
Node* left;
Node* right;
Node* random;
Node(int _val) {
val = _val;
left = nullptr;
right = nullptr;
random = nullptr;
}
};
class Solution {
public:
unordered_map<Node*, Node*> oldToNew;
Node* clone(Node* node) {
if (!node) return nullptr;
if (oldToNew.count(node)) return oldToNew[node];
Node* copy = new Node(node->val);
oldToNew[node] = copy;
copy->left = clone(node->left);
copy->right = clone(node->right);
copy->random = clone(node->random);
return copy;
}
Node* copyRandomBinaryTree(Node* root) {
return clone(root);
}
};
// Definition for a Node.
class Node {
int val;
Node left;
Node right;
Node random;
Node(int val) { this.val = val; }
}
class Solution {
Map<Node, Node> oldToNew = new HashMap<>();
private Node clone(Node node) {
if (node == null) return null;
if (oldToNew.containsKey(node)) return oldToNew.get(node);
Node copy = new Node(node.val);
oldToNew.put(node, copy);
copy.left = clone(node.left);
copy.right = clone(node.right);
copy.random = clone(node.random);
return copy;
}
public Node copyRandomBinaryTree(Node root) {
return clone(root);
}
}
/**
* // Definition for a Node.
* function Node(val, left, right, random) {
* this.val = val;
* this.left = left;
* this.right = right;
* this.random = random;
* }
*/
var copyRandomBinaryTree = function(root) {
const oldToNew = new Map();
function clone(node) {
if (node === null) return null;
if (oldToNew.has(node)) return oldToNew.get(node);
const copy = new Node(node.val, null, null, null);
oldToNew.set(node, copy);
copy.left = clone(node.left);
copy.right = clone(node.right);
copy.random = clone(node.random);
return copy;
}
return clone(root);
};
Brute-force approach:
Here, N
is the number of nodes in the tree. The hash map enables constant-time access to any node's clone, making the algorithm efficient.
Cloning a binary tree with random pointers is best solved by mapping each original node to its clone during traversal. This ensures that all pointers—including random pointers, which may point anywhere—are set correctly and efficiently. By leveraging a hash map, we achieve O(N) time and space complexity, and the approach elegantly handles cycles and arbitrary random connections.