133. Clone Graph
题目
Given the head of a graph, return a deep copy (clone) of the graph. Each node in the graph contains a label
(int
) and a list (List[UndirectedGraphNode]
) of its neighbors
. There is an edge between the given node and each of the nodes in its neighbors.
OJ’s undirected graph serialization (so you can understand error output):
Nodes are labeled uniquely.
We use #
as a separator for each node, and ,
as a separator for node label and each neighbor of the node.
As an example, consider the serialized graph {0,1,2#1,2#2,2}
.
The graph has a total of three nodes, and therefore contains three parts as separated by #
.
- First node is labeled as
0
. Connect node0
to both nodes1
and2
. - Second node is labeled as
1
. Connect node1
to node2
. - Third node is labeled as
2
. Connect node2
to node2
(itself), thus forming a self-cycle.
Visually, the graph looks like the following:
1
/ \
/ \
0 --- 2
/ \
\_/
Note: The information about the tree serialization is only meant so that you can understand error output if you get a wrong answer. You don’t need to understand the serialization to solve the problem.
解题思路
遍历原图,遇到未遍历过的节点时,复制一个新节点。保持该节点在原图中的关系与新节点在新图中的关系相对应,将新节点加入新图中。为了在新图中快速找到与原图中相应的节点,可以用一个 unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> dict
存储对应的节点。
方法一:BFS
(1)如果原图头节点为空,则返回NULL;
(2)先复制一个原图的头节点,加入dict中,作为新图的头节点;
(3)创建一个队列,将原图头节点加入队列;
(4)直到队列未空,进行如下循环:取出队首节点(该节点为原图当前遍历到的节点,而dict[队首节点]
则是新图与该节点对应的节点),对于该节点的每个子节点,若dict中没有对应节点(dict[子节点]
不存在),则说明该节点之前未遍历到,则复制一个该子节点,加入dict中,并将该子节点加入队列中,将dict[子节点]
加入到新图中与队首节点对应的节点的字节点列表中。
(5)在第(3)步中,循环结束后,原图每个节点都经历过BFS,每遍历到一个新节点,都会复制一个节点加入新图中,并且维持新图中节点的相邻关系,因此(3)步骤结束后,新图便是原图的复制。将新图中对应的头节点dict[原图头节点]
返回即可。
代码如下:
/**
* Definition for undirected graph.
* struct UndirectedGraphNode {
* int label;
* vector<UndirectedGraphNode *> neighbors;
* UndirectedGraphNode(int x) : label(x) {};
* };
*/
class Solution {
public:
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if(!node) return NULL;
unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> dict;
queue<UndirectedGraphNode*> q;
q.push(node);
dict[node] = new UndirectedGraphNode(node->label);
while(!q.empty()){
UndirectedGraphNode* cur = q.front();
q.pop();
for( auto next: cur->neighbors){
if( dict.find(next) == dict.end()){
dict[next] = new UndirectedGraphNode(next->label);
q.push(next);
}
dict[cur]->neighbors.push_back(dict[next]);
}
}
return dict[node];
}
};
方法二:DFS
(1)如果原图头节点为空,则返回NULL;
(2)创建一个新的dict,以原图头节点为参数调用dfs递归函数,该函数参数有一个节点,返回一个从该节点开始深度优先拷贝原图后的图对应的节点。
(3)进行如下递归:如果dict中有对应参数node的节点,则直接返回dict[node]
,否则创建node的拷贝节点,加入dict中,对于node的每个子节点,用子节点调用dfs函数后返回的是从子节点开始深度优先拷贝原图后的图对应的节点,将每个字节点调用dfs后返回的节点加入dict[node]
的子节点列表中,则dict[node]
则是从node开始深度优先拷贝原图后的图node对应的节点,将dict[node]
返回。
(4)用原图头节点调用dfs函数后返回的即是拷贝原图后的图的首节点。
代码如下:
/**
* Definition for undirected graph.
* struct UndirectedGraphNode {
* int label;
* vector<UndirectedGraphNode *> neighbors;
* UndirectedGraphNode(int x) : label(x) {};
* };
*/
class Solution {
public:
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if(!node) return NULL;
unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> dict;
return dfs(dict, node);
}
UndirectedGraphNode* dfs(unordered_map<UndirectedGraphNode*, UndirectedGraphNode*> &dict, UndirectedGraphNode* node){
if( dict.find(node) != dict.end()) return dict[node];
dict[node] = new UndirectedGraphNode(node->label);
for( auto next: node->neighbors)
dict[node]->neighbors.push_back(dfs(dict, next));
return dict[node];
}
};