Data Structures

Clone Graph

3 months, 3 weeks ago ; 63 views
Share this

Clone Graph

We are given a graph represented by a collection of nodes and their neighbors. The goal is to clone this graph, creating a new graph with the same structure and values.

Here's my solution,

class Node:
    """
    Represents a node in a graph.
    """

    def __init__(self, val=0, neighbors=None):
        """
        Initializes a new Node.

        Args:
            val (int): The value associated with the node (default is 0).
            neighbors (List[Node]): List of neighboring nodes (default is an empty list).
        """
        self.val = val
        self.neighbors = neighbors if neighbors is not None else []


class Solution:
    """
    Provides a solution for cloning a graph.
    """

    def cloneGraph(self, node: Node) -> Node:
        """
        Clones the given graph starting from the specified node.

        Args:
            node (Node): The starting node to clone.

        Returns:
            Node: The cloned graph.
        """
        oldToNew = {}

        def dfs(node):
            """
            Performs depth-first search to clone the graph.

            Args:
                node (Node): The current node to process.

            Returns:
                Node: The cloned node.
            """
            if node in oldToNew:
                return oldToNew[node]

            copy = Node(node.val)
            oldToNew[node] = copy

            for nei in node.neighbors:
                copy.neighbors.append(dfs(nei))
            return copy

        return dfs(node) if node else None

Depth-First Search (DFS) with Hash Map

We can use depth-first search (DFS) to traverse the original graph and create a copy of each node.

To avoid duplicating nodes, we’ll use a hash map (oldToNew) to keep track of the mapping between original nodes and their corresponding cloned nodes.

The DFS function will recursively create the cloned nodes and their neighbors.

DFS Function (dfs)

The dfs function takes an input node and returns its cloned counterpart.

If the node is already in the oldToNew map, we return the corresponding cloned node.

Otherwise, we create a new node with the same value as the original node and add it to the map.

We then recursively process each neighbor of the original node, creating their cloned counterparts and connecting them appropriately.

Cloning Process

For each neighbor of the original node, we recursively call dfs(nei) to get the cloned neighbor.

We add this cloned neighbor to the neighbors list of the newly created cloned node.

This ensures that the cloned graph maintains the same structure as the original.

Time Complexity

The DFS process visits each node once, so the time complexity is O(V), where V is the number of nodes in the graph.

Space Complexity

We use additional space for the hash map (oldToNew) to store the mapping between original and cloned nodes. Therefore, the space complexity is O(V) as well.

Unit Tests

I have created some unit tests to verify the accuracy and robustness of the cloneGraph method in the Solution class. Below, I’ve provided a set of test cases using the unittest framework:

import unittest

class TestSolution(unittest.TestCase):
    def test_cloneGraph_single_node(self):
        # Test with a single node graph
        node1 = Node(1)
        s = Solution()
        cloned_node1 = s.cloneGraph(node1)
        self.assertEqual(cloned_node1.val, 1)
        self.assertEqual(len(cloned_node1.neighbors), 0)

    def test_cloneGraph_multiple_nodes(self):
        # Test with a graph containing multiple nodes
        node1 = Node(1)
        node2 = Node(2)
        node3 = Node(3)
        node1.neighbors = [node2, node3]
        node2.neighbors = [node1, node3]
        node3.neighbors = [node1, node2]

        s = Solution()
        cloned_node1 = s.cloneGraph(node1)

        # Check values
        self.assertEqual(cloned_node1.val, 1)
        self.assertEqual(cloned_node1.neighbors[0].val, 2)
        self.assertEqual(cloned_node1.neighbors[1].val, 3)

        # Check references (should be different objects)
        self.assertIsNot(cloned_node1, node1)
        self.assertIsNot(cloned_node1.neighbors[0], node2)
        self.assertIsNot(cloned_node1.neighbors[1], node3)

    def test_cloneGraph_empty_graph(self):
        # Test with an empty graph (None input)
        s = Solution()
        cloned_node = s.cloneGraph(None)
        self.assertIsNone(cloned_node)

if __name__ == "__main__":
    unittest.main()

Become a member
Get the latest news right in your inbox. We never spam!

Read next

Island Perimeter

 This solution seeks to find the perimeter of an island in a grid.  The problem considers a grid where each cell represents land (1) or … Read More

Kibsoft 3 months, 3 weeks ago . 76 views

Pacific Atlantic Waterflow

3 months, 3 weeks ago . 82 views