题目:
Clone an undirected graph. Each node in the graph contains a label
and a list of its neighbors
.
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 #
.
0
. Connect node 0
to both nodes 1
and 2
.1
. Connect node 1
to node 2
.2
. Connect node 2
to node 2
(itself), thus forming a self-cycle.Visually, the graph looks like the following:
1 / \ / \ 0 --- 2 / \ \_/
分析:
这个题目提供给我们一个已知的无向图,图上结点都有自己的值(label)还有和其他图结点的关系(包括和其他结点的连接关系,还有可能自己关联自己,形成环),要求我们要对这个已知图做一个“克隆”(有点类似于上次那题copy list的题目)
图上结点的数据结构:
class UndirectedGraphNode {
int label;
ArrayList<UndirectedGraphNode> neighbors;
UndirectedGraphNode(int x) {
label = x;
neighbors = new ArrayList<UndirectedGraphNode>();
}
};
解题思路:
首先,我们会想到,如果给你一个图上的结点,比如 结点0,它和结点 1 还有 结点 2 都有关联,如果我们要设置 结点0 的关联关系的List集合的话,如果结点 1 和结点 2已经存在的话,那么我们将不能再创建一遍已经存在的结点。
综上,
1. 我们会用一个HashMap<UndirectedGraphNode,UndirectedGraphNode> map, 来存储已经被我们new 出来的图上的结点
2. 为了能够把图上的所有结点都顺利的创建出来并且把它们的关联关系也确定好,我们需要有一个 队列, 先把 提供给我们的图上的一个结点放入 queue中,然后循环,取出队列中的“头结点”(tempNode),如果结点有和其他结点的关系List, 遍历关系结合List中的结点,如果结点不包括在map中,那么证明这个结点还没有被创建,此时我们copy一个该图结点,然后 map.put(OldNode, NewNode); 并把这个结点加入到新的结点的关系集合List中.
3. 为了避免“有环”(自己连接到自己的结点)的情况会一直重复,我们需要用一个 Set 集合来存下所有处理过的 图结点!
【讲得有点乱,具体看代码吧!】
AC代码:
package cn.xym.leetcode.copygraph; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.Queue; import java.util.Set; class UndirectedGraphNode { int label; ArrayList<UndirectedGraphNode> neighbors; UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); } }; public class Solution { public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { if (node == null) return null; //存已经copy的结点, 存入的entry的key为 旧图的node, //value为新图的node("copy旧图node的结点"). HashMap<UndirectedGraphNode,UndirectedGraphNode> map = new HashMap<UndirectedGraphNode,UndirectedGraphNode>(); map.put(node, new UndirectedGraphNode(node.label)); //初始化,先copy 第一个结点 node Set<UndirectedGraphNode> visitedSet = new HashSet<UndirectedGraphNode>(); //存放被处理过的图结点 Queue<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>(); //存放待处理的图结点 queue.add(node); //往队列中加入一个结点node while (!queue.isEmpty()){ //取出队头结点 UndirectedGraphNode tempNode = queue.remove(); //判断这个结点是否已经被处理过了(防止“环”) if (visitedSet.contains(tempNode)) continue; visitedSet.add(tempNode); //加入处理过结点的集合 /*处理当前结点的关系集合List*/ for (UndirectedGraphNode i : tempNode.neighbors){ if (!map.containsKey(i)){ UndirectedGraphNode copy = new UndirectedGraphNode(i.label); map.put(i, copy); map.get(tempNode).neighbors.add(copy); }else{ map.get(tempNode).neighbors.add(map.get(i)); } queue.add(i); } } return map.get(node); } }