DFS with Hash Map
Intuition
We can clone the graph using depth-first search while maintaining a hash map from original nodes to their clones. When we visit a node, we create its clone and store it in the map. Then we recursively clone all neighbors. If a neighbor has already been cloned (exists in the map), we reuse the existing clone instead of creating a new one. This prevents infinite loops caused by cycles in the graph and ensures each node is cloned exactly once.
Algorithm
- If the input node is null, return null.
- Create a hash map to store the mapping from original nodes to cloned nodes.
- Start DFS from the given node. Create a clone of the current node and add it to the map.
- For each neighbor of the current node, check if it already exists in the map.
- If the neighbor is already cloned, add the existing clone to the current clone's neighbor list.
- If not, recursively clone the neighbor and add the result to the current clone's neighbor list.
- Return the clone of the starting node.
O(V + E) where V is the number of nodes and E is the number of edgesSpaceO(V) for the hash map and recursion stackCode (C++ · Java · Python · Go)
class Solution {
public:
unordered_map<Node*, Node*> visited;
Node* cloneGraph(Node* node) {
if (!node) return nullptr;
if (visited.count(node)) {
return visited[node];
}
Node* clone = new Node(node->val);
visited[node] = clone;
for (Node* neighbor : node->neighbors) {
clone->neighbors.push_back(cloneGraph(neighbor));
}
return clone;
}
};class Solution {
private Map<Node, Node> visited = new HashMap<>();
public Node cloneGraph(Node node) {
if (node == null) return null;
if (visited.containsKey(node)) {
return visited.get(node);
}
Node clone = new Node(node.val);
visited.put(node, clone);
for (Node neighbor : node.neighbors) {
clone.neighbors.add(cloneGraph(neighbor));
}
return clone;
}
}class Solution:
def cloneGraph(self, node: 'Node') -> 'Node':
if not node:
return None
visited = {}
def dfs(node):
if node in visited:
return visited[node]
clone = Node(node.val)
visited[node] = clone
for neighbor in node.neighbors:
clone.neighbors.append(dfs(neighbor))
return clone
return dfs(node)func cloneGraph(node *Node) *Node {
if node == nil {
return nil
}
visited := make(map[*Node]*Node)
var dfs func(*Node) *Node
dfs = func(n *Node) *Node {
if clone, ok := visited[n]; ok {
return clone
}
clone := &Node{Val: n.Val}
visited[n] = clone
for _, neighbor := range n.Neighbors {
clone.Neighbors = append(clone.Neighbors, dfs(neighbor))
}
return clone
}
return dfs(node)
}