Problem 133

Abstract / Summary

Given a reference to a node in a connected undirected graph with next pointers return a deep copy of the entire graph.

Note

The full problem description, including helpful examples, can be found on LeetCode.

Python 0133.py

class Solution:

    def createEdges(self, node):
        if not node or node.val in self.edges:
            return

        self.edges[node.val] = []
        for i in node.neighbors:
            self.edges[node.val].append(i.val)
            self.createEdges(i)


    def cloneGraph(self, node: 'Node') -> 'Node':
        if not node:
            return None

        self.edges = {}
        self.createEdges(node)

        clone = {}
        for e in self.edges:
            clone[e] = Node(e)

        for e in self.edges:
            for other in self.edges[e]:
                clone[e].neighbors.append(clone[other])

        return clone[node.val]
28 lines | 682 bytes | submitted August 19, 2023 | GitHub   tab size 4 | low complexity

Difficulty

This problem is ranked as
easy medium hard

and has an acceptance rate of about 66% (3+ million submissions).

Typical patterns to solve this problem:
  • Breadth First Search
  • Depth First Search
  • Graph Theory
  • Hash Table
I solved 663 easy, 1250 medium and 309 hard problems

AI Disclaimer

Every single line of code was written by me, 100% from scratch, between August 2023 and August 2024.
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.

See this dedicated page for more details.
LeetCode profile | GitHub repo

Code Walkthrough

Overview

The provided implementation defines a Solution class that clones an undirected graph represented by nodes of type Node. The algorithm proceeds in two distinct phases. First, it traverses the original graph to build an adjacency map (self.edges) that records each node’s value and the values of its neighboring nodes. Second, it creates a new set of Node instances and wires their neighbor relationships according to the previously built map. The result is a deep copy of the input graph, with the same topology but independent node objects.

Phase 1 - Building the adjacency map

The method createEdges performs a depth-first traversal starting from a given node. It checks whether the node is None or has already been visited (its value appears in self.edges). If either condition holds, the recursion stops, preventing infinite loops on cyclic graphs and avoiding duplicate work.

def createEdges(self, node):
    if not node or node.val in self.edges:
        return

    self.edges[node.val] = []
    for i in node.neighbors:
        self.edges[node.val].append(i.val)
        self.createEdges(i)

Key actions in this phase:

  • Initialization of an empty list for the current node’s adjacency entry.
  • Iteration over each neighbor, appending the neighbor’s value to the list.
  • Recursive call on each neighbor to continue the traversal.

Because the method records a node’s value before recursing, any subsequent encounter of the same node is short-circuited by the node.val in self.edges guard. This handles graphs that contain cycles, self-loops, or multiple paths to the same node, ensuring each vertex is processed exactly once.

Phase 2 - Instantiating clone nodes

After the adjacency map is populated, cloneGraph creates a dictionary clone that maps each original node value to a newly allocated Node object with the same value but an initially empty neighbor list.

clone = {}
for e in self.edges:
    clone[e] = Node(e)

This step isolates node creation from neighbor wiring, allowing all node objects to exist before any references are established. The approach eliminates the need for on-the-fly creation during neighbor linking, which could otherwise require checking for the existence of a target node repeatedly.

Phase 3 - Reconstructing neighbor relationships

With all clone nodes in place, the algorithm iterates over the adjacency map a second time. For each entry, it looks up the corresponding clone node and appends the clones of its neighbors, using the pre-built clone dictionary for constant-time access.

for e in self.edges:
    for other in self.edges[e]:
        clone[e].neighbors.append(clone[other])

Because the neighbor lists are built from values rather than object references, the code avoids accidental sharing of neighbor lists between the original and cloned graphs. The final statement returns the clone that corresponds to the original entry point.

return clone[node.val]

Edge-case handling

The implementation explicitly checks for a None input at the start of cloneGraph. When the input graph is empty, the method returns None immediately, satisfying the contract for an empty graph.

The recursion guard node.val in self.edges ensures that graphs containing cycles, including self-referential nodes (a node that lists itself as a neighbor), do not cause infinite recursion. By marking a node as visited before exploring its neighbors, the algorithm safely processes any graph topology, regardless of connectivity or the presence of multiple components reachable from the start node.

Performance-related choices

The two-pass strategy-first building an adjacency map, then constructing nodes and linking neighbors-offers several performance benefits. Recording adjacency information as plain integer lists (self.edges[node.val] = []) provides fast appends and compact storage, avoiding the overhead of storing full node objects during traversal. The subsequent node creation loop runs in linear time relative to the number of distinct node values, and the neighbor-linking loop also runs linearly with respect to the total number of edges, because each edge is processed exactly once.

Using dictionaries (self.edges and clone) for lookups yields constant-time access when checking visitation status, creating a node, or retrieving a neighbor’s clone. This eliminates the need for linear scans to locate nodes, which would degrade performance on large graphs.

By separating node allocation from neighbor wiring, the code avoids repeated conditional checks for the existence of a neighbor’s clone during edge reconstruction. All clones are guaranteed to exist before any neighbor list is populated, allowing the inner loop to focus solely on appending references, which is a minimal-overhead operation.

Overall, the design leverages depth-first traversal for discovery, dictionary-based memoization for fast existence checks, and a clear two-phase construction pipeline to achieve an efficient deep copy of an arbitrary undirected graph.

written by openai gpt

ELI5 - Simplified Explanation

Imagine you have a drawing of a constellation made of stars connected by lines. This code is like building a perfect double of that constellation.

First, the code goes through the drawing starting from one star and follows every single line to find all the other stars it can reach. As it visits each star, it writes down the name of that star and the names of all the other stars it is connected to in a secret notebook. It keeps doing this until every star has been found and its friends have been written down.

Once the notebook is full of these lists, the code starts making a second set of blank stars that match the ones from the first drawing. It looks at the notebook again to see who should be connected to whom. It carefully draws new lines between these new stars to make sure they look exactly like the connections in the first drawing. After all the lines are drawn, a identical version of the original constellation is ready to play with.

written by google gemini

Code Quality

Several LLMs ranked my code quality on a scale from 1 (very poor) to 10 (outstanding):
n = 27 | median = 6 | μ = 5.96 | σ = 1.71

Complexity Analysis

Time: linear
As a rule of thumb, the maximum input size for one second execution time is
  • factorial: up to 10 elements
  • exponential: up to 20 elements
  • polynomial: a few thousand elements
  • loglinear: up to 100,000 elements
  • linear: a few million elements
  • logarithmic: a billion elements
  • constant: practically unlimited
generated automatically

Other Solutions

I wrote a basic crawler to find other solutions to that problem.
Obviously, I did that after I solved the problem myself.

In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.

And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.

(click on a column header to sort the table)
author
author solutions
www AlgoMonster C++ Python Java TS
WalkCCC C++ Python Java
leetcode.ca C++ Python Java C# JS Go TS
LeetcodeHelp C++ Python Java
MemoryLimitExceeded C++ Python
Progiez C++ Python Java
github begeekmyfriend C
BigEggStudy C#
black-shadows C++
bujosa Python
charles-wangkai Java
DimitrisJim C
everthis JS
fartem Ruby
FelixFan1122 C#
fengvyi C++
fpdjsns C++
gaosq0604 Python
gouthampradhan Java
haoel C++
JoshCrozier JS
keineahnung2345 C++
lennylxx C++
linouk23 C++
lkwq007 Python
luangong C++
MacJim C++
qiyuangong Python
sonugiri1043 C++
suxrobGM C#
trung-hn Python
varunu28 Java
vli02 C
wisdompeak C++
XiaotaoGuo C++
yuanliu666 Kotlin
zfang399 C++
AlgoMonster C++, Python, Java, TypeScript
WalkCCC C++, Python, Java
leetcode.ca C++, C#, Go, Java, JavaScript, Python, TypeScript
LeetcodeHelp C++, Java, Python
MemoryLimitExceeded Python, C++
Progiez C++, Java, Python
begeekmyfriend C
BigEggStudy C#
black-shadows C++, C++
bujosa Python
charles-wangkai Java
DimitrisJim C
everthis JavaScript
fartem Ruby
FelixFan1122 C#
fengvyi C++
fpdjsns C++
gaosq0604 Python
gouthampradhan Java
haoel C++
JoshCrozier JavaScript
keineahnung2345 C++
lennylxx C++
linouk23 C++
lkwq007 Python
luangong C++
MacJim C++
qiyuangong Python
sonugiri1043 C++
suxrobGM C#
trung-hn Python
varunu28 Java
vli02 C
wisdompeak C++
XiaotaoGuo C++
yuanliu666 Kotlin
zfang399 C++
53 links | 37 authors | 10 languages

Videos

These are a few popular YouTube videos for this problem:
YouTube video 'Clone graph | Leetcode #133'
Techdose 14 mins
Clone graph | Leetcode #133
YouTube video 'Clone Graph | Leetcode - 133 | Google, Facebook, Amazon | DFS+BFS | Explanation ➕ Live Coding🧑🏻‍💻'
codestorywithMIK 42 mins
Clone Graph | Leetcode - 133 | Google, Facebook, Amazon | DFS+BFS | Explanation ➕ Live Coding🧑🏻‍💻
YouTube video 'Clone Graph - Leetcode 133 - Graphs (Python)'
Greg Hogg 14 mins
Clone Graph - Leetcode 133 - Graphs (Python)
YouTube video '9. Clone Graph | Tricky Question | LeetCode 133 | Explained with Intuition - Simple C++, JAVA code'
Keerti Purswani 23 mins
9. Clone Graph | Tricky Question | LeetCode 133 | Explained with Intuition - Simple C++, JAVA code
YouTube video 'Clone Graph | Leetcode 133 | DFS | Day-23'
Ayushi Sharma 19 mins
Clone Graph | Leetcode 133 | DFS | Day-23
YouTube video 'LeetCode #133: Clone Graph | Facebook Coding Interview | Amazon Coding Interview'
Knowledge Center 17 mins
LeetCode #133: Clone Graph | Facebook Coding Interview | Amazon Coding Interview
YouTube video 'CLONE GRAPH | LEETCODE # 133 | PYTHON BFS SOLUTION'
Cracking FAANG 10 mins
CLONE GRAPH | LEETCODE # 133 | PYTHON BFS SOLUTION
YouTube video 'Clone Graph || Leetcode 133 || Variant Question Big Tech Actually Asks'
Coding with Minmer 20 mins
Clone Graph || Leetcode 133 || Variant Question Big Tech Actually Asks
YouTube video 'clone graph | clone graph leetcode | leetcode 133 | bfs | dfs'
Naresh Gupta 11 mins
clone graph | clone graph leetcode | leetcode 133 | bfs | dfs
YouTube video '[Java] Leetcode 133. Clone Graph [Search #7]'
Eric Programming 13 mins
[Java] Leetcode 133. Clone Graph [Search #7]
YouTube video 'Clone Graph | Live Coding with Explanation | Leetcode - 133'
Algorithms Made Easy 6 mins
Clone Graph | Live Coding with Explanation | Leetcode - 133
YouTube video 'Clone Graph - LeetCode 133 - Python #blind75 #leetcode #clonegraph'
Deepti Talesra 17 mins
Clone Graph - LeetCode 133 - Python #blind75 #leetcode #clonegraph
YouTube video 'Clone Graph - LeetCode 133 - JavaScript'
AlgoJS 10 mins
Clone Graph - LeetCode 133 - JavaScript
YouTube video 'Clone Graph| Leetcode 133 | Live coding session 🔥🔥 | BFS traversal'
Coding Decoded 12 mins
Clone Graph| Leetcode 133 | Live coding session 🔥🔥 | BFS traversal
YouTube video 'Clone Graph - 133. LeetCode - Java'
Teddy Smith 7 mins
Clone Graph - 133. LeetCode - Java
YouTube video '133 || Clone Graph || C++ || Leetcode Daily Challenge'
CodeFreaks 11 mins
133 || Clone Graph || C++ || Leetcode Daily Challenge
YouTube video 'Leetcode 133: Clone Graph in Telugu | BFS + HashMap | Python DSA | srkcodes'
Srk Codes 13 mins
Leetcode 133: Clone Graph in Telugu | BFS + HashMap | Python DSA | srkcodes
YouTube video 'Facebook Coding Interview Question | Leetcode 133 | Clone Graph'
WorkWithGoogler 13 mins
Facebook Coding Interview Question | Leetcode 133 | Clone Graph
YouTube video 'Daily Leetcode #1103: Apr 08, 2023 - 133. Clone Graph'
Programming Live with Larry 13 mins
Daily Leetcode #1103: Apr 08, 2023 - 133. Clone Graph
YouTube video 'Daily Leetcode #694: Feb 23, 2022 - 133. Clone Graph'
Programming Live with Larry 10 mins
Daily Leetcode #694: Feb 23, 2022 - 133. Clone Graph
20 videos   did my crawler come up with invalid videos ? drop me a line.

Similar Problems

1 similar problem

Solved On The Same Day

2 easy 6 medium 1 hard
10 solutions   August 19, 2023

Extra

There are a few extra pages giving you some insights into my setup:
  • Tech Stack - my development environment and tools
  • AI - how AI helped me create this website (NOT solving the problems)
  • Progress - progression over time
  • Quality - code quality