Clone Graph
Deep-copy an undirected connected graph — BFS/DFS with a map from original node to clone, neighbor wiring pitfalls.
- dsa
- graph
- interview
- Meta
- Amazon
- Microsoft
The problem
Given a reference to a node in a connected undirected graph, return a deep copy of the entire graph. Each node has a value and a list of neighbors.
// 1 -- 2
// | |
// 4 -- 3
// clone must have new node objects, same connectivity
Cycles exist. A naïve recursive clone without a map infinite-loops.
Brute idea that fails
JSON serialize — nodes aren’t trees; cycles break it. Copying only the start node’s neighbor array by reference shares structure. You need a visited map: old → new.
Optimal: DFS or BFS with clone map
DFS
class Node {
val: number;
neighbors: Node[];
constructor(val = 0, neighbors: Node[] = []) {
this.val = val;
this.neighbors = neighbors;
}
}
function cloneGraph(node: Node | null): Node | null {
if (!node) return null;
const map = new Map<Node, Node>();
function dfs(n: Node): Node {
if (map.has(n)) return map.get(n)!;
const copy = new Node(n.val);
map.set(n, copy); // set before recursing — breaks cycles
for (const nei of n.neighbors) {
copy.neighbors.push(dfs(nei));
}
return copy;
}
return dfs(node);
}
BFS
function cloneGraphBfs(node: Node | null): Node | null {
if (!node) return null;
const map = new Map<Node, Node>();
map.set(node, new Node(node.val));
const q: Node[] = [node];
let head = 0;
while (head < q.length) {
const cur = q[head++];
const curCopy = map.get(cur)!;
for (const nei of cur.neighbors) {
if (!map.has(nei)) {
map.set(nei, new Node(nei.val));
q.push(nei);
}
curCopy.neighbors.push(map.get(nei)!);
}
}
return map.get(node)!;
}
| Time | O(V + E) |
| Space | O(V) for map + queue/stack |
Walk a 2-node cycle
1 ⇄ 2
- Clone 1, map{1→1’}.
- Neighbor 2 not cloned → clone 2, map{2→2’}.
- 2’s neighbor 1 already in map → push 1’, not re-enter.
- 1’s neighbors get 2’. Done.
Edge cases
nullinput →null- Single node with empty neighbors
- Single node with self-loop (rare in LC; handle via map)
- Dense graph — O(V+E) still
Common mistakes
- Mapping by
valonly (vals can theoretically collide in variants; use node identity) - Creating the clone after recursing (cycle → stack overflow)
- Shallow copy of
neighborsarray
Interview delivery
- Deep copy + cycles ⇒ hash map.
- Register clone before exploring neighbors.
- Implement DFS or BFS fully.
- Null and single-node cases.
- O(V+E).
Mental model
Cloning a graph is “map identity while traversing.” The map serves two jobs: (1) return the already-built clone when you re-encounter a node, (2) break infinite recursion on cycles. You must map.set(original, copy) before walking neighbors — same discipline as copying structures with back-edges.
Frontend analogy: cloning a component tree with circular refs (parent pointers) or duplicating a scene graph in a canvas editor.
BFS vs DFS — pick one and finish
DFS is shorter. BFS is safer on deep graphs if recursion limits worry you (JS engines ~thousands of frames). Either is O(V+E). Don’t mix half-BFS half-DFS mid coding.
Out-loud answer
“Deep copy of undirected connected graph. HashMap old→new. Create clone, register in map, then wire neighbors recursively or with a queue. Null input returns null. Time and space linear in vertices plus edges.”
Related
- Course Schedule
- Number of Islands
- Copy List with Random Pointer — same map pattern
- Pacific Atlantic Water Flow
- JavaScript Interview Guide