题目大意
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
class Node {
public int val;
public List<Node> neighbors;
}
输入:adjList = [[2,4],[1,3],[2,4],[1,3]]
输出:[[2,4],[1,3],[2,4],[1,3]]
解释:
图中有 4 个节点。
节点 1 的值是 1,它有两个邻居:节点 2 和 4 。
节点 2 的值是 2,它有两个邻居:节点 1 和 3 。
节点 3 的值是 3,它有两个邻居:节点 2 和 4 。
节点 4 的值是 4,它有两个邻居:节点 1 和 3 。
解题思路
题目要求深度拷贝,因此应该重新创建每个节点,而不能用另一个指针指向原节点。
我们用一个map记录已经被深度拷贝过的节点(只是创建了该节点,邻居指向不一定完成)。
另外创建一个队列,如果当前节点的某个邻居节点没有被克隆(即,没有在map中),则将其克隆放入map中,然后加入队列。
每次从队列中弹出一个节点,找到他的所有邻居节点(如果没克隆的话,先把邻居节点克隆),然后让该节点的克隆节点指向所有邻居节点的克隆节点。直到队列为空,完成操作。
使用队列的话看作是广度优先遍历,使用栈的话看作是深度优先遍历。
class Solution {
public:
Node* cloneGraph(Node* node) {
if (!node){
return nullptr;
}
// 创建一个map,用于记录节点是否被克隆过,且通过原节点找到克隆节点
unordered_map<Node*, Node*> dict;
// 队列用于接受还没有完成邻居指向的节点
// 刚克隆的节点一定没完成邻居指向,因此克隆过后立刻放入队列中
queue<Node*> q;
dict[node] = new Node(node->val);
q.push(node);
while (!q.empty()){
// 弹出队列中的某个节点
Node * curNode = q.front(); q.pop();
// 遍历该节点的邻居节点
for (Node * heighbor : curNode->neighbors){
// 如果该邻居节点还没完成克隆,就将其克隆一下,然后将该邻居节点放入队列
if (!dict.count(heighbor)){
dict[heighbor] = new Node(heighbor->val);
q.push(heighbor);
}
// 让当前节点的克隆节点指向当前节点的邻居节点的克隆节点
dict[curNode]->neighbors.push_back(dict[heighbor]);
}
}
return dict[node];
}
};```