[Leetcode解題] 133. Clone Graph - 使用 DFS 解
2 August 2024
medium
dfs
133. Clone Graph
題目描述
133. Clone Graph 給定一個連通無向圖中的一個節點的引用。請返回這個圖的深拷貝(克隆)。
每個節點包含一個整數值和一個鄰居列表(List[Node]
)。
節點的定義如下:
class Node:
def __init__(self, val=0, neighbors=[]):
self.val = val
self.neighbors = neighbors
解題思路
-
使用hash-table(哈希表)記錄節點的對應關系:我們需要一個辦法來記錄每個已經訪問過的節點,以防止無限迴圈的發生。同時hash-table來存儲原節點和對應克隆節點的映射關系,這樣可以方便地查找和避免重複創建節點。
- 深度優先搜索(DFS)或廣度優先搜索(BFS)遍歷圖:對於這類圖的深度複製問題,可以用「深度優先搜索(DFS)」或者「廣度優先搜索(BFS)」來解決。以下我們使用 DFS 方法。
- 建立鄰居關系:對於每個節點的所有鄰居,如果已經創建就從哈希表中取出對應的克隆節點,否則會先克隆這個節點,並將其添加到當前克隆節點的鄰居列表中。
要深拷貝一個圖,需要確保每個節點及其鄰居都被完整地複製,並且原圖中的節點間的連接在新圖中也得到相應的反映。這可以通過下列步驟實現:
- 創建一個哈希表來存儲已經複製過的節點,key是原節點,value是複製的節點。
- 使用 DFS 進行遍歷,每次遍歷到一個節點時:
- 如果節點已經在哈希表中,直接返回其對應的複製節點。
- 如果節點不在哈希表中,創建一個新的節點,並將其加入哈希表。
- 遞迴地複製所有鄰居節點,並更新新節點的鄰居列表。
Python代碼實現
"""
# 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 []
"""
from typing import Optional
class Solution:
def __init__(self):
self.node_map = {}
def cloneGraph(self, node: Optional['Node']) -> Optional['Node']:
if not node:
return None
if node in self.node_map:
return self.node_map[node]
new_node = Node(node.val)
self.node_map[node] = new_node
for neighbor in node.neighbors:
new_node.neighbors.append(self.cloneGraph(neighbor))
return new_node
C++ 代碼實現
/*
// Definition for a Node.
class Node {
public:
int val;
vector<Node*> neighbors;
Node() {
val = 0;
neighbors = vector<Node*>();
}
Node(int _val) {
val = _val;
neighbors = vector<Node*>();
}
Node(int _val, vector<Node*> _neighbors) {
val = _val;
neighbors = _neighbors;
}
};
*/
class Solution {
public:
unordered_map<Node*, Node*> nodeMap;
Node* cloneGraph(Node* node) {
if (!node) return nullptr;
Node*& newNode = nodeMap[node];
if (newNode) return newNode;
newNode = new Node(node-> val);
for(const auto &n: node->neighbors){
newNode->neighbors.push_back(cloneGraph(n));
}
return newNode;
}
};
時間複雜度
這個解法的時間複雜度為$O(N+E)$,其中 $N$ 是圖中節點的數量,$E$是邊的數量。我們需要訪問每個節點並創建其對應的克隆節點,每個節點只被訪問一次,每個邊也只被創建一次。