一、原题
Clone an undirected graph. Each node in the graph contains alabeland a list of itsneighbors.
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 as0. Connect node0to both nodes1and2.
- Second node is labeled as1. Connect node1to node2.
- Third node is labeled as2. Connect node2to node2(itself), thus forming a self-cycle.
Visually, the graph looks like the following:
1 / \ / \ 0 --- 2 / \ \_/
二、中文
克隆无向图。图中的每一个节点包含一个label
和 一组neighbors
.
本题中的无向图的定义为:
每个节点都是唯一标记的。
我们通过#
来划分每一个节点
,
通过,来划分节点标记和节点的每一个邻居。
举个例子,给定一个图{0,1,2#1,2#2,2}
.
这个图中共3个节点,因此包含了通过#
划分的三个部分
.
1.第一个节点被标记为 0.连接节点0和节点1
and 2
.
2.第二个节点被标记为 1.将节点1和 节点2相连接.
3.第三个节点被标记为 2. 将节点2和节点2(它自身)想连接,这样就形成了自环.
这个图就如下面所示:
1
/ \
/ \
0 --- 2
/ \
\_/
三、举例
共两种方法,DFS--递归, BFS--队列
拷贝方法是用用HashMap,key存原始值,value存copy的值,用DFS或者BFS方法遍历帮助拷贝neighbors的值。
但这里有个问题,在clone一个节点时我们需要clone它的neighbors,而邻居节点有的已经存在,有的未存在,如何进行区分?
这里我们使用Map来进行区分,Map的key值为原来的node,value为新clone的node,当发现一个node未在map中时说明这个node还未被clone,
四、思路
也是使用两种方法,包括 DFS 和 BFS 两个方式,首先广度优先遍历使用的是队列的方式,而 DFS 使用的是递归的方式,也就是获得一个结点之后再对这个结点进行递归。
这个还使用到了一个 Map 的机构,通过 Map 的结构来保存现在结点和新的结点这样一个键值对,这样就可以观察当前结点是否遍历过了,然后将当前结点和他的邻居结点存一下。
五、程序
import java.util.HashMap;
import java.util.Map;
import java.util.LinkedList;
/**
* Definition for undirected graph.
* class UndirectedGraphNode {
* int label;
* ArrayList<UndirectedGraphNode> neighbors;
* UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); }
* };
*/
public class Solution {
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
HashMap<UndirectedGraphNode, UndirectedGraphNode> map =
new HashMap<UndirectedGraphNode, UndirectedGraphNode>();
if(node == null){
return null;
}
//使用BFS广度优先遍历,所以需要建立以队列
LinkedList<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>();
//复制一新的头结点
UndirectedGraphNode head = new UndirectedGraphNode(node.label);
//将新的头结点以map的方式来存入进去,用来查找是否已经访问过了
map.put(node, head);
queue.add(node);
while(!queue.isEmpty()){
UndirectedGraphNode curNode = queue.poll();
//遍历当前结点的邻居,将所有的邻居也进行保存
for(UndirectedGraphNode everyNeigh : curNode.neighbors){
//如果集合中没有,也就是这个结点没有遍历过
if(!map.containsKey(everyNeigh)){
//将结点添加到集合中
queue.add(everyNeigh);
UndirectedGraphNode newNeighbor = new UndirectedGraphNode(everyNeigh.label);
map.put(everyNeigh, newNeighbor);
}
//复制邻居结点,也就是将当前结点的所有邻居结点进行复制
map.get(curNode).neighbors.add(map.get(everyNeigh));
}
}
return head;
}
//下面是DFS深度优先遍历
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
if(node == null){
return null;
}
HashMap<UndirectedGraphNode, UndirectedGraphNode> map =
new HashMap<UndirectedGraphNode, UndirectedGraphNode>();
//也是初始化一个新的结点
UndirectedGraphNode head = new UndirectedGraphNode(node.label);
//map中存入结点
map.put(node, head);
//然后进行深度优先遍历
DFS(map, node);
return head;
}
public void DFS(HashMap<UndirectedGraphNode, UndirectedGraphNode> map, UndirectedGraphNode node){
if(node == null){
return;
}
//当前结点的所有邻居结点
for(UndirectedGraphNode everyNeigh : node.neighbors){
if(!map.containsKey(everyNeigh)){
//如果没有包含
UndirectedGraphNode newNeighbor = new UndirectedGraphNode(everyNeigh.label);
//将结点存入map中
map.put(everyNeigh, newNeighbor);
//进行DFS的遍历
DFS(map, everyNeigh);
}
//复制邻居结点,也就是将当前结点的所有邻居结点进行复制
map.get(node).neighbors.add(map.get(everyNeigh));
}
}
}