Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.
Java Solution 1 – DFS
HashMap<Node, Node> map = new HashMap<>(); public Node cloneGraph(Node node) { map.put(node, new Node(node.val, new ArrayList<>())); for(Node neighbor: node.neighbors){ if(map.containsKey(neighbor)){ map.get(node).neighbors.add(map.get(neighbor)); }else{ map.get(node).neighbors.add(cloneGraph(neighbor)); } } return map.get(node); } |
Java Solution 2 – BFS
public Node cloneGraph(Node node) { Map<Node, Node> map = new HashMap<>(); Queue<Node> queue = new ArrayDeque<>(); queue.offer(node); map.put(node, new Node(node.val, new ArrayList<>())); while (!queue.isEmpty()) { Node h = queue.poll(); for (Node neighbor : h.neighbors) { if (!map.containsKey(neighbor)) { map.put(neighbor, new Node(neighbor.val, new ArrayList<>())); queue.offer(neighbor); } map.get(h).neighbors.add(map.get(neighbor)); } } return map.get(node); } |
The Time complexity for cloning the graph is O(V+E) and thats because we
shall be traversing each vertex of the graph from the Queue and then
visiting each edge E atleast once.
What would be the time complexity?
A DFS with alreadyAvailable map that stores (label,new node)
And if node is present in map, use it else create a new node and put in map.
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
if (node == null)
return node;
Map alreadyAvailable = new HashMap();
return cloneGraphHelper(node,alreadyAvailable);
}
private UndirectedGraphNode cloneGraphHelper(UndirectedGraphNode node, Map alreadyAvailable) {
if ( alreadyAvailable.containsKey(node.label) )
return alreadyAvailable.get(node.label);
UndirectedGraphNode returnNode = new UndirectedGraphNode(node.label);
alreadyAvailable.put(node.label,returnNode);
for(UndirectedGraphNode N: node.neighbors)
returnNode.neighbors.add(cloneGraphHelper(N,alreadyAvailable));
return returnNode;
}
Why should it be bfs ? why not dfs??
import java.util.HashSet;
import java.util.Set;
public class CloneGraph {
public static UndirectedGraphNode cloneGraph(UndirectedGraphNode root1) {
if(root1==null){
return null;
}
UndirectedGraphNode root2;
Set visited=new HashSet();
root2=cloneGraph(root1, visited);
return root2;
}
private static UndirectedGraphNode cloneGraph(UndirectedGraphNode root1, Set visited){
visited.add(root1.label);
UndirectedGraphNode root2=new UndirectedGraphNode(root1.label);
for(UndirectedGraphNode node:root1.neighbors){
root2.neighbors.add(node);
if(!visited.contains(node.label)){
cloneGraph(node, visited);
}
}
return root2;
}
}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class Solution {
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
if (node == null) {
return null;
}
HashMap hasProcessed
= new HashMap();
return cloneGraph(node, hasProcessed);
}
private UndirectedGraphNode cloneGraph(UndirectedGraphNode node,
HashMap hasProcessed) {
UndirectedGraphNode newNode = new UndirectedGraphNode(node.label);
hasProcessed.put(node, newNode);
for (UndirectedGraphNode next : node.neighbors) {
if (hasProcessed.get(next) == null) {
newNode.neighbors.add(cloneGraph(next, hasProcessed));
} else {
newNode.neighbors.add(hasProcessed.get(next));
}
}
return newNode;
}
}
Great code. I just wonder whether it should be queue.poll( ), instead of queue.pop( )?
How about the following algorithm in C++? I don’t think we need to use BFS when copying a whole graph. A whole graph can’t be represented by a single node but by a list of node. So I think the following approach works too. The most important thing to clone a whole graph is using hash map between original node and cloned node, not the BFS.
struct node {
int v;
vector E;
node(int v) : v(v) {}
};
auto clone_graph = [](const vector& G) {
vector retG(G.size(), nullptr);
unordered_map node_map;
for (size_t i = 0; i v };
retG[i]->E.resize(G[i]->E.size());
node_map[G[i]] = retG[i];
}
for (size_t i = 0; i < retG.size(); ++i) {
for (size_t j = 0; j E.size(); ++j) {
retG[i]->E[j] = node_map[G[i]->E[j]];
}
}
return retG;
};
Here is another approach which is using BFS.
auto clone_graph2 = [](const vector& G) {
unordered_map cloned;
function impl = [&](node* o) {
queue q;
cloned[o] = new node(o->v);
cloned[o]->E.resize(o->E.size());
q.push(o);
while (!q.empty()) {
auto n = q.front();
q.pop();
for (size_t i = 0; i E.size(); ++i) {
if (cloned.find(n->E[i]) == cloned.end()) {
q.push(n->E[i]);
cloned[n->E[i]] = new node(n->E[i]->v);
cloned[n->E[i]]->E.resize(n->E[i]->E.size());
}
cloned[n]->E[i] = cloned[n->E[i]];
}
}
return cloned[o];
};
vector retG(G.size(), nullptr);
for (size_t i = 0; i < retG.size(); ++i) {
retG[i] = cloned.find(G[i]) == cloned.end() ? impl(G[i]) : cloned[G[i]];
}
return retG;
};
I prefer the first approach for its simplicity
Thanks for your comment. I want to read your code, can you put your code inside <pre></pre> tags?
Thanks X Wang!
I used a modified depth first search
/**
* Definition for undirected graph.
* class UndirectedGraphNode {
* int label;
* List neighbors;
* UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList(); }
* };
*/
public class Solution {
private Map marked = new HashMap();
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
if (node==null) return null;
UndirectedGraphNode result = new UndirectedGraphNode(node.label);
marked.put(node.label, result);
for (int i=0; i<node.neighbors.size(); i++) {
UndirectedGraphNode toClone = node.neighbors.get(i);
UndirectedGraphNode neighbor;
if (!marked.containsKey(toClone.label)) {
neighbor = cloneGraph(toClone);
} else { neighbor = marked.get(toClone.label); }
result.neighbors.add(neighbor);
}
return result;
}
}