1 题目
题目:克隆图(Clone Graph)
描述:克隆一张无向图。无向图的每个节点包含一个 label 和一个列表 neighbors。保证每个节点的 label 互不相同。程序需要返回一个经过深度拷贝的新图。新图和原图具有同样的结构, 并且对新图的任何改动不会对原图造成任何影响。
lintcode题号——137,难度——medium
样例1:
输入:
{1,2,4#2,1,4#4,1,2}
输出:
{1,2,4#2,1,4#4,1,2}
解释:
1------2
\ |
\ |
\ |
\ |
4
关于图的序列化规则:
{1,2,4#2,1,4#3,5#4,1,2#5,3} 序列表示的图如下
1------2 3
\ | |
\ | |
\ | |
\ | |
4 5
序列中使用 # 分隔节点信息。
1,2,4 表示 2和4 是1的相邻节点;
2,1,4 表示 1和4 是2的相邻节点;
3,5 表示 5 是3的相邻节点;
4,1,2 表示 1和2 是4的相邻节点;
5,3 表示 3 是5的相邻节点。
2 解决方案
2.1 思路
题意是对一个无向图进行深度拷贝,可以考虑先拷贝节点,再新旧节点之间进行映射,使我们能够通过旧节点找到新节点,再拷贝边,即将旧节点的邻居所映射的新节点,作为新邻居赋给该旧节点所映射的新节点。
需要注意的是,很容易将旧邻居直接赋给新节点,这样是错误的,因为旧节点对应的邻居也是旧的,需要各自找到映射的新邻居。
2.2 时间复杂度
图上的宽度优先搜索,算法的时间复杂度为O(n+m),其中n为节点数,m为边数。
因为在图中的m的数量级最高是n的平方,所以也可以认为是O(m)。
2.3 空间复杂度
图上的宽度优先搜索,使用了queue队列数据结构保存节点,算法的空间复杂度为O(n)。
3 源码
细节:
- 使用宽度优先搜索获取所有点;
- 克隆所有点,并映射新旧节点,需要从旧节点向新节点映射;
- 旧点->旧邻居们->新邻居们,连接新点与新邻居们。
C++版本:
/**
* Definition for undirected graph.
* struct UndirectedGraphNode {
* int label;
* vector<UndirectedGraphNode *> neighbors;
* UndirectedGraphNode(int x) : label(x) {};
* };
*/
/**
* @param node: A undirected graph node
* @return: A undirected graph node
*/
UndirectedGraphNode* cloneGraph(UndirectedGraphNode* node) {
// write your code here
if (node == NULL)
{
return NULL;
}
// 获取所有点
set<UndirectedGraphNode *> setOldNodes = traverseNode(node);
// 克隆节点,建立旧节点到新节点的映射
map<UndirectedGraphNode *, UndirectedGraphNode *> mapNodes;
for (auto n : setOldNodes)
{
mapNodes.insert(make_pair(n, new UndirectedGraphNode(n->label)));
}
// 克隆边
for (auto n : setOldNodes)
{
for (auto neighbor : n->neighbors)
{
mapNodes.at(n)->neighbors.push_back(mapNodes.at(neighbor));
}
}
return mapNodes.at(node);
}
set<UndirectedGraphNode *> traverseNode(UndirectedGraphNode * root)
{
queue<UndirectedGraphNode *> nodeQueue;
set<UndirectedGraphNode *> nodeSet;
nodeQueue.push(root);
nodeSet.insert(root);
while (!nodeQueue.empty())
{
UndirectedGraphNode * cur = nodeQueue.front();
nodeQueue.pop();
for (auto n : cur->neighbors)
{
if (nodeSet.find(n) != nodeSet.end())
{
continue;
}
nodeSet.insert(n);
nodeQueue.push(n);
}
}
return nodeSet;
}