Description
Given a reference of a node in a connected undirected graph.
Return a deep copy (clone) of the graph.
Each node in the graph contains a value (int) and a list (List[Node]) of its neighbors.
class Node {
public int val;
public List<Node> neighbors;
}Test case format:
For simplicity, each node’s value is the same as the node’s index (1-indexed). For example, the first node with val == 1, the second node with val == 2, and so on. The graph is represented in the test case using an adjacency list.
An adjacency list is a collection of unordered lists used to represent a finite graph. Each list describes the set of neighbors of a node in the graph.
The given node will always be the first node with val = 1. You must return the copy of the given node as a reference to the cloned graph.
Example 1:

Input: adjList = [[2,4],[1,3],[2,4],[1,3]]
Output: [[2,4],[1,3],[2,4],[1,3]]
Explanation: There are 4 nodes in the graph.
1st node (val = 1)‘s neighbors are 2nd node (val = 2) and 4th node (val = 4).
2nd node (val = 2)‘s neighbors are 1st node (val = 1) and 3rd node (val = 3).
3rd node (val = 3)‘s neighbors are 2nd node (val = 2) and 4th node (val = 4).
4th node (val = 4)‘s neighbors are 1st node (val = 1) and 3rd node (val = 3).
Example 2:

Input: adjList = [[]]
Output: [[]]
Explanation: Note that the input contains one empty list. The graph consists of only one node with val = 1 and it does not have any neighbors.
Example 3:
Input: adjList = []
Output: []
Explanation: This an empty graph, it does not have any nodes.
Constraints:
- The number of nodes in the graph is in the range
[0, 100]. 1 <= Node.val <= 100Node.valis unique for each node.- There are no repeated edges and no self-loops in the graph.
- The Graph is connected and all nodes can be visited starting from the given node.
Primary Approach: DFS with HashMap ( Time, Space)
Intuition
Cloning a graph requires duplicating every node and re-establishing all directed/undirected edges between the newly cloned nodes:
- Use a
HashMap(originalNode -> clonedNode) to keep track of already created clones. This serves as both ourvisitedset and a mapping lookup. - Traverse the graph using Depth-First Search (DFS) starting from
node. - If the current node is already in the map, return its saved clone (prevents infinite recursion on cycles).
- Otherwise, instantiate a new
Node(node.val), register it in theHashMap, and recursively clone all of its neighbors to populate itsneighborslist.
import java.util.HashMap;
import java.util.Map;
class Solution {
private Map<Node, Node> visited = new HashMap<>();
public Node cloneGraph(Node node) {
if (node == null) return null;
// Return cloned instance if already visited to break cycles
if (visited.containsKey(node)) {
return visited.get(node);
}
// Create deep copy for current node
Node cloneNode = new Node(node.val);
visited.put(node, cloneNode);
// Recursively clone all neighbors
for (Node neighbor : node.neighbors) {
cloneNode.neighbors.add(cloneGraph(neighbor));
}
return cloneNode;
}
}
Complexity
- Time Complexity: — Every vertex and edge in the graph is visited exactly once.
- Space Complexity: —
HashMapstores key-value pairs, and the recursion call stack takes up to depth in a linear graph.
Alternative Approach: BFS with HashMap ( Time, Space)
Intuition
Perform a level-by-level traversal using an explicit Queue:
- Store cloned nodes in a
HashMap(originalNode -> clonedNode). - Push the starting
nodeinto aQueueand insert its clone into theHashMap. - While the queue is not empty, poll
curr. For eachneighborincurr.neighbors:- If
neighborhasn’t been cloned yet, create its clone, put it in the map, and pushneighborto the queue. - Add
visited.get(neighbor)tovisited.get(curr).neighbors.
- If
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
class Solution {
public Node cloneGraph(Node node) {
if (node == null) return null;
Map<Node, Node> visited = new HashMap<>();
Queue<Node> queue = new ArrayDeque<>();
// Initialize root clone and BFS queue
visited.put(node, new Node(node.val));
queue.add(node);
while (!queue.isEmpty()) {
Node curr = queue.poll();
for (Node neighbor : curr.neighbors) {
// If neighbor hasn't been cloned yet, clone and queue it
if (!visited.containsKey(neighbor)) {
visited.put(neighbor, new Node(neighbor.val));
queue.add(neighbor);
}
// Connect cloned current node to cloned neighbor
visited.get(curr).neighbors.add(visited.get(neighbor));
}
}
return visited.get(node);
}
}
Complexity
- Time Complexity: — Each node and edge is processed once during queue operations.
- Space Complexity: — Queue holds at most nodes, and
HashMapstores cloned nodes.
Key Interview Discussion Points
- Why
HashMapis Necessary: Graph nodes can contain cycles (e.g., ). Without aHashMapmapping original nodes to cloned instances, simple traversal would result in infinite loops or duplicated node creations. - Deep Copy Verification: Remind the interviewer that returning original node references within neighbor lists violates deep copying requirements; every newly linked neighbor must point strictly to newly allocated
Nodememory addresses.
Easy Memory Rule
“HashMap stores
original -> clonedTraverse via DFS/BFS If cloned return it, else create clone, map it, and recursively populateneighbors!”