Leetcode 133. Clone Graph

这篇博客介绍了如何解决LeetCode上的133题——克隆图。作者首先分析了问题需求,明确了需要从给定节点开始构建整个图的副本。接着讨论了使用广度优先搜索(BFS)和深度优先搜索(DFS)两种算法的思路,并解释了为何在DFS中需要使用字典来存储节点信息,而在BFS中则需要使用队列。最后,作者指出两种算法的时间复杂度和空间复杂度相同,并认为在本题中两者效果相当。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Please see the question below and what I am trying to do here is how I think and solve the problem

Original question:
https://leetcode.com/problems/clone-graph/

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).

When I get this question, I have to think about what need to be returned. It asked that clone/copy the graph, so first thing came to my mind is I need a graph! Yes, but how can I get a graph, yes, it is from a node, and than we assign value and find its neighbors. Who could be our starting node? Why not using original node as a starting point? Good idea.

Ok, so next thing is that how I can find its value and its neighbors? This is more like a question of what algorithms I should use. For those type of questions, since we need to traversal all the nodes/points, so either BFS or DFS should works. BFS go level by level and DFS go one node and access as deep as possible.

Probably we need a visit set as well since we need to memory which nodes already visited or not. How we can achieve this? A set, a list or a something else?

I would like to try depth first search, I will need a dfs which traversal all nodes, something like:

    def dfs(self,node):
        if not node:
            return
        copy_node=Node(node.val,[])
        for nei in node.neighbors:
                copy_node.neighbors.append(n)
        return copy_node

Is there any problem here? Yes, we dont have a visit set I discussed earlier, so we don’t know which nodes already visited. How about we add a set? Set should be better than list, what will be the problem? Let’s say if I create a set and all it could do is just tell me I visited or not. What if I visited? If I visited, if I visited, I need to get all its information as well, like its val and its neighbor. Let’s I visited node1, and I dfs its neighbors, I entered node 2, I am checking neighbors of node 2, 1 is neighbor, so I dfs, in the newer recurrsion, I am asking, did I visited node 1, the answer is yes, so I need to attach node 1 as neighbor to node 2, when I attach, I need entire node 1 information such as val and node 1 neighbors, not just checking visited or not.

To solve this issue, it leads to think using dictionary instead of set or list, I can check key as used as visited or not, and return it value which should be a Node type and contains all necessary information. Ok, let’s finished it up:

"""
Definition for a Node.

class Node:
    def __init__(self, val = 0, neighbors = None):
        self.val = val
        self.neighbors = neighbors if neighbors is not None else []
"""

class Solution:
    def cloneGraph(self, node: 'Node') -> 'Node':
        res=self.dfs(node,{})
        return res
    
    def dfs(self,node,memo):
        if not node:
            return
        if node in memo:
            return memo[node]
        copy_node=Node(node.val,[])
        memo[node]=copy_node
        for nei in node.neighbors:
            n=self.dfs(nei,memo)
            if n:
                copy_node.neighbors.append(n)
        return copy_node

This should work, let’s try BFS than.

if we wanna do BFS, we need a queue, in Python, we can have collections.deque which provide us a nice popleft function. We need to append node level by level and attach information into its neighbors. Again, like DFS, when we accessed a node, if we visited, we just want to get all information from this node such as val and neighbors, so we will need a dictionary as well to save those info. Everytime we popleft a node, we checking its neighbors, we haven’t visited, we add into the queue and created necessary inforation in the dictionary. And finally we attach all its information.

Below will be code:

"""
Definition for a Node.
class Node:
    def __init__(self, val = 0, neighbors = None):
        self.val = val
        self.neighbors = neighbors if neighbors is not None else []
"""

class Solution:
    def cloneGraph(self, node: 'Node') -> 'Node':
        copy_node=Node(node.val,[])
        queue=collections.deque()
        queue.append(copy_node)
        d={node:copy_node}
        
        while queue:
            node=queue.popleft()
            for nei in node.neighbors:
                if nei not in d:
                    d[nei]=Node(nei.val,[])
                    queue.append(nei)
                d[node].neighbors.append(d[nei])
        
        return copy_node

Ok, not it is time to discuss which method/algorithms is better. Most of the time we using BFS to search short path as if we get the answer we just return right way, both algorithms take O(m*n) and O(n) as time complexity and space memory usage. In terms of this question, as we need to clone, we anyway need to go throguht all the nodes, it is not finding a solution or built a path, I would say they should be pretty much the same, whichever you like. here m represents how many nodes and n represents how many connections each node can access. It should no worse than that time complexity.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值