from typing import Optional
class Solution:
def cloneGraph(self, node: Optional["Node"]) -> Optional["Node"]:
if not node:
return None
start = node
o_to_n = {}
stk = [start]
visited = set()
visited.add(start)
while stk:
node = stk.pop()
o_to_n[node] = Node(val=node.val)
for nei in node.neighbors:
if nei not in visited:
visited.add(nei)
stk.append(nei)
for old_node, new_node in o_to_n.items():
for nei in old_node.neighbors:
new_nei = o_to_n[nei]
new_node.neighbors.append(new_nei)
return o_to_n[start]
# Time Complexity: O(V+E)
# Space Complexity: O(V)
In the Clone Graph problem, you're given a reference node from a connected undirected graph. Each node contains a value and a list of neighbors. The task is to create a deep copy of the entire graph, such that each node in the new graph is a completely new object with identical structure and connections.
The major challenge in cloning a graph lies in preserving the structure while avoiding infinite loops due to cycles. Additionally, since nodes reference each other via their neighbors, we must ensure each original node maps to exactly one newly created node.
The approach uses Depth-First Search (DFS) or Breadth-First Search (BFS) with a hash map to keep track of cloned nodes:
First, handle the base case: if the input node is null
, return null
.
Next, initialize a hash map (let's call it o_to_n
) that will map each original node to its corresponding cloned node.
Then, define a recursive DFS function that:
o_to_n
.Finally, invoke the DFS function starting with the input node and return the resulting cloned node. The graph will be fully copied.
Since we visit each node exactly once and clone it, the time complexity is O(n), where n
is the number of nodes in the graph.
The space complexity is also O(n) due to the hash map and recursion stack (in case of DFS).
Cloning graphs is a fundamental task in many domains such as: