Clone Graph

1 Clone Graph

题目:

Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors.


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 #.

  1. First node is labeled as 0. Connect node 0 to both nodes 1 and 2.
  2. Second node is labeled as 1. Connect node 1 to node 2.
  3. Third node is labeled as 2. Connect node 2 to node 2 (itself), thus forming a self-cycle.

 

Visually, the graph looks like the following:

       1
      / \
     /   \
    0 --- 2
         / \
         \_/

 解析:

1 先复制节点,再复制节点的neighbors关系。

2 label是唯一的,可以用label作为Map的key,以确定哪些节点已经复制。

 代码如下:

 1 package leetcode;
 2 
 3 import java.util.ArrayList;
 4 import java.util.HashMap;
 5 import java.util.HashSet;
 6 import java.util.List;
 7 import java.util.Map;
 8 import java.util.Set;
 9 
10 public class CloneGraph {
11     class UndirectedGraphNode {
12         int label;
13         List<UndirectedGraphNode> neighbors;
14         Set<UndirectedGraphNode> set = new HashSet<CloneGraph.UndirectedGraphNode>();
15 
16         UndirectedGraphNode(int x) {
17             label = x;
18             neighbors = new ArrayList<UndirectedGraphNode>();
19         }
20 
21         public String toString(Set<UndirectedGraphNode> set) {
22             if (set.contains(this)) {
23                 return "";
24             }
25             set.add(this);
26 
27             String s = label + ",";
28             for (UndirectedGraphNode neighbor : neighbors) {
29                 s += neighbor.label + ",";
30             }
31             s += "#";
32 
33             for (UndirectedGraphNode neighbor : neighbors) {
34                 s += neighbor.toString(set);
35             }
36             return s;
37         }
38 
39         @Override
40         public String toString() {
41             set.clear();
42             return toString(set);
43         }
44     };
45 
46     private void cloneNode(UndirectedGraphNode node, Map<Integer, UndirectedGraphNode> map) {
47 
48         if (map.containsKey(node.label)) {
49             return;
50         }
51         
52         UndirectedGraphNode nodeClone = new UndirectedGraphNode(node.label);
53         map.put(node.label, nodeClone);
54         for (UndirectedGraphNode neighbor : node.neighbors) {
55             cloneNode(neighbor, map);
56         }
57         return;
58     }
59 
60     private void cloneNeighbors(UndirectedGraphNode node, UndirectedGraphNode nodeClone, Map<Integer, UndirectedGraphNode> map) {
61         
62         if (node.neighbors.size() == nodeClone.neighbors.size()) {
63             return;
64         }
65         
66         for (UndirectedGraphNode neighbor : node.neighbors) {
67             nodeClone.neighbors.add(map.get(neighbor.label));
68         }
69         
70         for (UndirectedGraphNode neighbor : node.neighbors) {
71             cloneNeighbors(neighbor, map.get(neighbor.label), map);
72         }
73     }
74 
75     public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
76         if (node == null) {
77             return null;
78         }
79 
80         // 复制节点
81         Map<Integer, UndirectedGraphNode> map = new HashMap<Integer, UndirectedGraphNode>();
82         cloneNode(node, map);
83         
84         UndirectedGraphNode nodeClone = map.get(node.label);
85 
86         // 复制neighbors关系
87         cloneNeighbors(node, nodeClone, map);
88         
89         return nodeClone;
90     }
91 }
View Code

2 题外话

本题有坑:

(1) 无向图,node2是node1的neighbors,不代表node1是node2的neighbors。

本来是准备将nodeClone挂到node的最后一个neighbors,然后复制nodeClone的neighbors关系,再断开node和nodeClone的连接。

这样时间复杂度为O(n),空间复杂度O(1)。

这么做的瓶颈在于最后无法区分哪些是node的节点,哪些是clone的节点。这个需要存在如下假设:有node1.neighbors.contains(node2),则必有node2.neighbors.contains(node1)。

(2) 本题label唯一不通用,可以取node作为Map的key,这就需要为UndirectedGraphNode添加node的hashCode()和equals()方法,而leetcode是不允许修改这个的。一方面,平时我们是可以修改类的;另一方面,我们可以创建UndirectedGraphNode的子类,计算完成后,将结果强转为父类。

 

posted @ 2014-08-29 14:04  yanyichao  阅读(115)  评论(0编辑  收藏  举报