题目描述:
Clone an undirected graph. Each node in the graph contains a label
and a list of its neighbors
.
OJ's undirected graph serialization:
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 / \ \_/
程序代码:
解法1:BFS
/**
* Definition for undirected graph.
* struct UndirectedGraphNode {
* int label;
* vector<UndirectedGraphNode *> neighbors;
* UndirectedGraphNode(int x) : label(x) {};
* };
*/
class Solution {
public:
map<UndirectedGraphNode*, UndirectedGraphNode*> visit;
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if (node == NULL)
return NULL;
// 只有一个连通分量,不需要循环
if (visit.find(node) == visit.end()) {
bfs(node);
}
return visit[node];
}
void bfs(UndirectedGraphNode *node) {
// 用原node的label新建并映射一个新的newNode
UndirectedGraphNode* newNode = new UndirectedGraphNode(node->label);
visit[node] = newNode;
// 建立队列
queue<UndirectedGraphNode*> q;
q.push(node);
// 循环直到队列为空
while (!q.empty()) {
UndirectedGraphNode* temp = q.front();
vector<UndirectedGraphNode*> neighbor = temp->neighbors;
q.pop();
// 遍历访问点的邻接点
for (vector<UndirectedGraphNode*>::iterator it = neighbor.begin(); it != neighbor.end(); ++it) {
// 判断若没visit过,则复制旧邻接点生成一个新的node
if (visit.find(*it) == visit.end()) {
UndirectedGraphNode* newNode2 = new UndirectedGraphNode((*it)->label);
visit[*it] = newNode2;
q.push(*it);
}
// 将新node加入邻接点
visit[temp]->neighbors.push_back(visit[*it]);
}
}
}
};
解法2: DFS
class Solution {
public:
map<UndirectedGraphNode*, UndirectedGraphNode*> visit;
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if (node == NULL)
return NULL;
// 只有一个连通分量,不需要循环所有连通分量
// 若没有visit过
if (visit.find(node) == visit.end()) {
dfs(node);
}
return visit[node];
}
void dfs(UndirectedGraphNode* node) {
// 用原node的label新建并映射一个新的newNode
UndirectedGraphNode* newNode = new UndirectedGraphNode(node->label);
visit[node] = newNode;
// 遍历原node的邻居
vector<UndirectedGraphNode*> neighbor = node->neighbors;
for (vector<UndirectedGraphNode*>::iterator it = neighbor.begin(); it != neighbor.end(); ++it) {
UndirectedGraphNode* temp = *it;
// 用dfs进行递归,得到各个邻居
if (visit.find(*it) == visit.end()) {
dfs(*it);
}
// 加入邻居节点
newNode->neighbors.push_back(visit[*it]);
}
}
};
解法3:稍微简化的dfs
class Solution {
public:
map<UndirectedGraphNode*, UndirectedGraphNode*> visit;
UndirectedGraphNode *cloneGraph(UndirectedGraphNode *node) {
if (node == NULL)
return NULL;
// 只有一个连通分量,不需要循环所有连通分量
return dfs(node);
}
UndirectedGraphNode* dfs(UndirectedGraphNode* node) {
// 若没有visit过
if (visit.find(node) == visit.end()) {
// 用原node的label新建并映射一个新的newNode
UndirectedGraphNode* newNode = new UndirectedGraphNode(node->label);
visit[node] = newNode;
// 遍历原node的邻居
vector<UndirectedGraphNode*> neighbor = node->neighbors;
for (vector<UndirectedGraphNode*>::iterator it = neighbor.begin(); it != neighbor.end(); ++it) {
UndirectedGraphNode* temp = *it;
// 用dfs进行递归,得到各个邻居
newNode->neighbors.push_back(dfs(temp));
}
}
return visit[node];
}
};
简要题解:
本题是一道关于图的问题。用到bfs和dfs算法。
先理清题意。本题的输入是一个无向图,要求复制这个无向图并输出。题中还给出了无向图节点的结构,包括一个唯一的label和一个vector,该向量中包含邻接节点。
很自然地,我想到使用bfs和dfs算法来解决这道问题。不过这道问题中有一个关键,就是visit数组要如何表示。因为不知道节点的总数量n,所以建立一个数组显然是不行的了,于是我想到使用stl库中的map来表示visit。 一开始,我打算用map<int, bool>来表示,即用每个节点唯一的label来映射一个布尔值,表示是否访问过,这也是最基本和普通的方法。但这样做了以后,我发现表示起来非常麻烦,既然都使用了map,不如直接将原节点映射到复制的节点,即用map<UndirectedGraphNode*, UndirectedGraphNode*>来表示,这样在表示访问了的同时,还可以直接映射到复制后的节点,操作起来就方便了很多。
接着,按常规的bfs的思路,建立队列,加入元素,循环取出元素,并处理节点元素中的向量,将新复制好的向量元素放入复制好的节点的邻接点向量中即可。
用dfs处理时同样简单,对邻接点向量中的每个元素递归调用dfs函数即可。
此外,我的解法3还对解法2的dfs做了稍微的简化,将解法2中void的dfs函数改为返回UndirectedGraphNode*,这样递归时可以直接将dfs(temp)加入邻接点向量,写起来稍微简单些。但也要注意,这样写的话cloneGraph函数中就没有了判断是否visit过的语句(因为直接return dfs(node)了),需要在dfs函数开始时加上这一句。
通过本题,我复习了一下关于图和dfs、bfs的知识点,接下来我还会再对其他知识点进行复习。