Clone Graph
Problem
Node stores an int val and a List<Node> neighbors.
Build a deep copy: brand-new nodes with the same values and the same edges (in the same
neighbour order), sharing no object with the original. Return the copy of the given node
(or null for an empty graph).adj = [[2,4],[1,3],[2,4],[1,3]]Output[[2,4],[1,3],[2,4],[1,3]]adj = [[]]Output[[]]adj = []Output[]0 ≤ nodes ≤ 100 · 1 ≤ val ≤ 100, unique (node i has val i) · no self-loops or repeated edges · graph is connected
Try it yourself
class Solution {
public Node cloneGraph(Node node) {
}
}
Instinct Connected regions, all paths, reachability, cloning or 2-colouring a graph or grid: dive from a node, mark it, recurse into unvisited neighbours.
Memory hack Mark before you march: go deep, paint as you go, and back up only when every door is already painted.
Open the Graph DFS guide →Approaches
Brute ForceTwo Passes: Copy Nodes, then Wire Edges
O(V + E)Space O(V)Split the job. Pass 1: BFS over the original graph and create a bare
copy of every node in a map. Pass 2: walk every original edge
u → v and append copy(v) to copy(u). Since
all clones exist before wiring, no edge can point to a missing node.
public Node cloneGraph(Node node) { if (node == null) return null; Map<Node, Node> copy = new HashMap<>(); Deque<Node> q = new ArrayDeque<>(List.of(node)); copy.put(node, new Node(node.val)); while (!q.isEmpty()) { // pass 1: discover + create copies Node cur = q.poll(); for (Node nb : cur.neighbors) if (!copy.containsKey(nb)) { copy.put(nb, new Node(nb.val)); q.add(nb); } } for (Map.Entry<Node, Node> e : copy.entrySet()) // pass 2: wire edges for (Node nb : e.getKey().neighbors) e.getValue().neighbors.add(copy.get(nb)); return copy.get(node); }
Easy to reason about, but traverses the graph twice and needs a queue plus a map.
OptimalOne-Pass DFS with Clone Map
O(V + E)Space O(V)cloneGraph(x) returns the clone of x: if it is
already in the map, return it; otherwise create it, register it first, then
recursively clone each neighbour and append the result. Registering before
recursing is what makes a cycle 1–2–1 terminate.
private final Map<Node, Node> clones = new HashMap<>(); public Node cloneGraph(Node node) { if (node == null) return null; if (clones.containsKey(node)) return clones.get(node); Node copy = new Node(node.val); clones.put(node, copy); // register BEFORE recursing to break cycles for (Node nb : node.neighbors) copy.neighbors.add(cloneGraph(nb)); return copy; }
Single traversal, minimal code; recursion depth is at most V (≤ 100 here).
Node[101] array can replace the hash
map; for very deep graphs switch to the BFS form to avoid stack overflow.At a glance
| Level | Approach | Time | Space |
|---|---|---|---|
| Brute Force | Two Passes: Copy Nodes, then Wire Edges | O(V + E) | O(V) |
| Optimal | One-Pass DFS with Clone Map | O(V + E) | O(V) |
- Putting the clone in the map after the recursive calls — infinite recursion on cycles.
- Reusing
node.neighborsin the copy — a shallow copy, not a clone. - Forgetting the
null(empty graph) input.
- Name the map's two jobs out loud: visited-set and old→new lookup.
- Clarify directed vs undirected — the same code works for both.
- Mention this is the graph version of Copy List with Random Pointer.