133. 克隆图
133. 克隆图
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
class Node {
public int val;
public List<Node> neighbors;
}
public int val;
public List<Node> neighbors;
}
测试用例格式:
简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1(val = 1),第二个节点值为 2(val = 2),以此类推。该图在测试用例中使用邻接列表表示。
邻接列表 是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。
输入: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 。
输出:[[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 。
输入:adjList = [[]]
输出:[[]]
解释:输入包含一个空列表。该图仅仅只有一个值为 1 的节点,它没有任何邻居。
输出:[[]]
解释:输入包含一个空列表。该图仅仅只有一个值为 1 的节点,它没有任何邻居。
![](https://common.cnblogs.com/images/loading.gif)
输入:adjList = []
输出:[]
解释:这个图是空的,它不含任何节点。
提示:
节点数不超过 100 。
每个节点值 Node.val 都是唯一的,1 <= Node.val <= 100。
无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
图是连通图,你可以从给定节点访问到所有节点。
每个节点值 Node.val 都是唯一的,1 <= Node.val <= 100。
无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
图是连通图,你可以从给定节点访问到所有节点。
思路:
方法一:深度优先搜索 DFS 沿给定节点的邻居节点一直搜索到最后。
1.从给定节点开始遍历图。
2.使用一个 HashMap 存储所有已被访问和复制的节点。HashMap 中的 key 是原始图中的节点,value 是克隆图中的对应节点。如果某个节点已经被访问过,则返回其克隆图中的对应节点。
3.如果当前访问的节点不在 HashMap 中,则创建它的克隆节点存储在 HashMap 中。注意:在进入递归之前,必须先创建克隆节点并保存在 HashMap 中。
时间复杂度 o(n), 空间复杂度 o(n)
代码:
/* // 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 { unordered_map<Node*, Node*> visited; public: Node* cloneGraph(Node* node) { if(!node) return node; unordered_map<Node*, Node*>::iterator it = visited.find(node); if(it!=visited.end()) return it->second; Node *new_node; new_node = new Node(node->val); visited[node] = new_node; int i, len = node->neighbors.size(); for(i = 0; i < len; i++) { new_node->neighbors.push_back(cloneGraph(node->neighbors[i])); } return new_node; } };
思路:用栈迭代实现 DFS
1.从给定节点开始遍历图,创建该节点对应的新节点,并将该节点压入栈中。
2.使用一个 HashMap 存储所有已被访问和复制的节点。HashMap 中的 key 是原始图中的节点,value 是克隆图中的对应节点。如果某个节点 A 的邻节点已经被访问过,将该邻接点加入 A 的邻接表中。如果 A 的所有邻节点都被访问过,将 A 从栈中弹出。
3.如果当前访问的节点A 的邻节点不在 HashMap 中,则创建它的克隆节点存储在 HashMap 中,并将该节点压入栈中,同时清空 A 的邻节点。
代码:
/*
// 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) {
unordered_map<Node*, Node*> visited;
stack<Node*> st;
if(!node)
return node;
Node *new_node, *old_node;
Node *old_node1, *new_node1;
new_node = new Node(node->val);
visited[node] = new_node;
st.push(node);
int i, len, flag = 1;
while(!st.empty())
{
old_node = st.top();
len = old_node->neighbors.size();
new_node = visited[old_node];
unordered_map<Node*, Node*>::iterator it;
flag = 1;
for(i = 0; i< len; i++)
{
old_node1 = old_node->neighbors[i];
it = visited.find(old_node1);
if(it!=visited.end())
{
new_node->neighbors.push_back(it->second);
}
else
{
new_node1 = new Node(old_node1->val);
visited[old_node1] = new_node1;
st.push(old_node1);
flag = 0;
break;
}
}
if(flag)
{
st.pop();
}
else
{
new_node->neighbors.clear();
}
}
return visited[node];
}
};
/* // 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 node; unordered_map<Node*, Node*> visited; Node *new_node, *old_node, *head; stack<Node*> deal; new_node = new Node(node->val); visited[node] = new_node; deal.push(node); head = new_node; int i, len; while(!deal.empty()) { old_node = deal.top(); deal.pop(); len = old_node->neighbors.size(); unordered_map<Node*, Node*>::iterator it = visited.find(old_node); new_node = it->second; for(i = 0; i < len; i++) { new_node->neighbors.push_back(copy(old_node->neighbors[i], visited, deal)); } } return head; } Node *copy(Node *old_node1, unordered_map<Node*,Node*>&visited, stack<Node*>&deal) { unordered_map<Node*, Node*>::iterator it = visited.find(old_node1); if(it!=visited.end()) return it->second; else { Node *new_node1; new_node1 = new Node(old_node1->val); visited[old_node1] = new_node1; deal.push(old_node1); return new_node1; } } };
思路:广度优先遍历 BFS 利用队列
使用 HashMap 存储所有访问过的节点和克隆节点。HashMap 的 key 存储原始图的节点,value 存储克隆图中的对应节点。visited 用于防止陷入死循环,和获得克隆图的节点。
将第一个节点添加到队列。克隆第一个节点添加到名为 visited 的 HashMap 中。
BFS 遍历
从队列首部取出一个节点。
遍历该节点的所有邻接点。
如果某个邻接点已被访问,则该邻接点一定在 visited 中,那么从 visited 获得该邻接点。
否则,创建一个新的节点存储在 visited 中。并将该节点加入队列。
将克隆的邻接点添加到克隆图对应节点的邻接表中。
遍历该节点的所有邻接点。
如果某个邻接点已被访问,则该邻接点一定在 visited 中,那么从 visited 获得该邻接点。
否则,创建一个新的节点存储在 visited 中。并将该节点加入队列。
将克隆的邻接点添加到克隆图对应节点的邻接表中。
时间复杂度 o(n), 空间复杂度o(n)
代码
/* // 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 node; unordered_map<Node*, Node*> visited; Node *new_node, *old_node, *head; queue<Node*> deal; new_node = new Node(node->val); visited[node] = new_node; deal.push(node); head = new_node; int i, len; while(!deal.empty()) { old_node = deal.front(); deal.pop(); len = old_node->neighbors.size(); unordered_map<Node*, Node*>::iterator it = visited.find(old_node); new_node = it->second; for(i = 0; i < len; i++) { new_node->neighbors.push_back(copy(old_node->neighbors[i], visited, deal)); } } return head; } Node *copy(Node *old_node1, unordered_map<Node*,Node*>&visited, queue<Node*>&deal) { unordered_map<Node*, Node*>::iterator it = visited.find(old_node1); if(it!=visited.end()) return it->second; else { Node *new_node1; new_node1 = new Node(old_node1->val); visited[old_node1] = new_node1; deal.push(old_node1); return new_node1; } } };
posted on 2020-08-02 00:57 Little-Prince 阅读(143) 评论(0) 编辑 收藏 举报