标签:
https://leetcode.com/problems/clone-graph/
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 / \_/
解题思路:
这道题看似复杂,其实不是太难。主要用到两个知识。
1. 用图的广度优先遍历来遍历每个node。
2. 用深拷贝的方式去拷贝每个node和它的neighbor,这里包含用map去寻找每个原label对应的新node。因为同一个label,已经new过的,就不要再new了。这个思路和 Copy List with Random Pointer 这道题很像。
/** * Definition for undirected graph. * class UndirectedGraphNode { * int label; * List<UndirectedGraphNode> neighbors; * UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); } * }; */ public class Solution { public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { if(node == null) { return node; } Queue<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>(); Map<Integer, UndirectedGraphNode> map = new HashMap<Integer, UndirectedGraphNode>(); Set<Integer> set = new HashSet<Integer>(); UndirectedGraphNode root = new UndirectedGraphNode(node.label); queue.offer(node); map.put(root.label, root); while(queue.size() > 0) { UndirectedGraphNode current = queue.poll(); if(set.contains(current.label)) { continue; } set.add(current.label); for(UndirectedGraphNode neighbor : current.neighbors) { queue.add(neighbor); UndirectedGraphNode temp; if(map.containsKey(neighbor.label)) { temp = map.get(neighbor.label); } else { temp = new UndirectedGraphNode(neighbor.label); } UndirectedGraphNode currentCopy = map.get(current.label); currentCopy.neighbors.add(temp); map.put(temp.label, temp); } } return root; } }
上面的代码借助了一个额外的set,用来维护当前已经处理过neighbor的node,因为map中的node仅仅是已经new过的node,应该比处理过的node要多。
后来看了别人的代码,其实这个set是可以省去的。重点在于,queue其实是一个“待处理”的队列,只有new一个新node时,才将其加入。
这样,比如我处理到第二个node,遍历它的邻居是,第一个node因为已经处理过,也还是不会被加入queue的。这样避免了循环的问题。
而前一个思路是,将当前遍历的node的全部neighbor都加入queue,然后再去判断它是否已经处理过,显然是繁琐了。
必须要注意,后一种解法也是最常用的BFS中处理这种问题的方法,必须记住。
/** * Definition for undirected graph. * class UndirectedGraphNode { * int label; * List<UndirectedGraphNode> neighbors; * UndirectedGraphNode(int x) { label = x; neighbors = new ArrayList<UndirectedGraphNode>(); } * }; */ public class Solution { public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) { if(node == null) { return node; } Queue<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>(); Map<Integer, UndirectedGraphNode> map = new HashMap<Integer, UndirectedGraphNode>(); // Set<Integer> set = new HashSet<Integer>(); UndirectedGraphNode root = new UndirectedGraphNode(node.label); queue.offer(node); map.put(root.label, root); while(queue.size() > 0) { UndirectedGraphNode current = queue.poll(); // if(set.contains(current.label)) { // continue; // } // set.add(current.label); for(UndirectedGraphNode neighbor : current.neighbors) { UndirectedGraphNode temp; if(map.containsKey(neighbor.label)) { temp = map.get(neighbor.label); } else { temp = new UndirectedGraphNode(neighbor.label); // 可以不用set,重点在于把下面一行移到这里 queue.add(neighbor); } UndirectedGraphNode currentCopy = map.get(current.label); currentCopy.neighbors.add(temp); map.put(temp.label, temp); } } return root; } }
标签:
原文地址:http://www.cnblogs.com/NickyYe/p/4447898.html