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.
本題的目的就是複製一個給定的 graph。我們可以分別用 BFS 跟 DFS 走訪每個 node 並複製,然後也將其連接的 nodes 複製並接上。
完整程式碼如下:
/*
// 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:
Node* cloneGraph(Node* node) {
if (!node)
return NULL;
unordered_map<Node*, Node*> visit;
queue<Node*> q;
q.push(node);
visit[node] = new Node(node->val);
while (!q.empty()) {
Node *cur = q.front();
q.pop();
for (Node* neighbor: cur->neighbors){
if (visit.find(neighbor) == visit.end()) {
visit[neighbor] = new Node(neighbor->val);
q.push(neighbor);
}
visit[cur]->neighbors.push_back(visit[neighbor]);
}
}
return visit[node];
}
};
當我們每走訪一個 node,因為是 BFS,所以我們在每次走訪一個 node 就可以先把該 node 複製並且把它相鄰的 node 也都複製並且接上 (第 36-42 行)。
但因為每個相鄰 node 也都可能會是其它 node 的相鄰的 node 所以可能早就複製過了,所以我們會需要一個紀錄每個 node 有沒有被走訪的 map unordered_map<Node*, Node*> visit
,這個 map 的第一個指標是存原本的 node,第二個指標是存複製過後的 node。
我們每次要複製走訪 node 的相鄰 node 前只要查這個 map 看有沒有存在該 node 的指標就知道有沒有被複製過 (第 37-39 行),而只有還沒複製過的相鄰 node 會需要之後再走訪,因為還沒複製過也就代表這個 node 還沒有被走訪,因此它的複製的 node 也還沒有接上其他相鄰的複製的 nodes。
完整程式碼如下:
/*
// 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:
Node* dfs(Node *node, unordered_map<Node*, Node*> &visit) {
Node *copy = new Node(node->val);
visit[node] = copy;
for (int i=0; i<node->neighbors.size(); ++i) {
Node *neighbor = node->neighbors[i];
if (visit.find(neighbor) == visit.end()) {
Node *copy_neighbor = dfs(neighbor, visit);
copy->neighbors.push_back(copy_neighbor);
}
else {
copy->neighbors.push_back(visit[neighbor]);
}
}
return visit[node];
}
Node* cloneGraph(Node* node) {
if (!node)
return node;
unordered_map<Node*, Node*> visit;
return dfs(node, visit);
}
};
相較於 BFS,DFS 不會一次就把走訪的 node 的相鄰 nodes 都複製,而是選擇其中一個相鄰的 node 複製然後再以該 node 繼續往下走訪並遞迴的做此動作。
所以每次複製一個 node DFS 的做法並不會一次就接上該 node 的相鄰 node 的複製,而是一次只接一個複製的相鄰 node,而此複製的相鄰 node 就是下一次要走訪的 node。
跟 BFS 一樣的是每當要複製正在走訪的 node 的相鄰 node 前,我們都要去檢查 visit
map,看看此 node 是不是已經有在走訪其他 node 時就已經複製過了。如果已經複製過了就不需要複製並且走訪,只需要把它已經複製的 node 接上正在走訪的 node 即可。
這類需要做 graph search 一定會走訪所有的 nodes 且至少也會走訪每一條邊一遍,因為要判斷是否要走訪相鄰的 nodes,所以需要的時間複雜度為
空間複雜度上,BFS 的 queue 最多會需要存