题目描述(中等难度)
复制一个图,图的节点定义如下。
class Node { public int val; public List<Node> neighbors; public Node() {} public Node(int _val,List<Node> _neighbors) { val = _val; neighbors = _neighbors; } };
neighbors
是一个装 Node
的 list
,因为对象的话,java
变量都存储的是引用,所以复制的话要新 new
一个 Node
放到 neighbors
。
思路分析
这个题其实就是对图进行一个遍历,通过 BFS
或者 DFS
。需要解决的问题就是怎么添加当前节点的 neighbors
,因为遍历当前节点的时候,它的邻居节点可能还没有生成。
解法一 BFS
先来一个简单粗暴的想法。
首先对图进行一个 BFS
,把所有节点 new
出来,不处理 neighbors
,并且把所有的节点存到 map
中。
然后再对图做一个 BFS
,因为此时所有的节点已经创建了,只需要更新所有节点的 neighbors
。
public Node cloneGraph(Node node) { if (node == null) { return node; } //第一次 BFS Queue<Node> queue = new LinkedList<>(); Map<Integer, Node> map = new HashMap<>(); Set<Integer> visited = new HashSet<>(); queue.offer(node); visited.add(node.val); while (!queue.isEmpty()) { Node cur = queue.poll(); //生成每一个节点 Node n = new Node(); n.val = cur.val; n.neighbors = new ArrayList<Node>(); map.put(n.val, n); for (Node temp : cur.neighbors) { if (visited.contains(temp.val)) { continue; } queue.offer(temp); visited.add(temp.val); } } //第二次 BFS 更新所有节点的 neightbors queue = new LinkedList<>(); queue.offer(node); visited = new HashSet<>(); visited.add(node.val); while (!queue.isEmpty()) { Node cur = queue.poll(); for (Node temp : cur.neighbors) { map.get(cur.val).neighbors.add(map.get(temp.val)); } for (Node temp : cur.neighbors) { if (visited.contains(temp.val)) { continue; } queue.offer(temp); visited.add(temp.val); } } return map.get(node.val); }
当然再仔细思考一下,其实我们不需要两次 BFS
。
我们要解决的问题是遍历当前节点的时候,邻居节点没有生成,那么我们可以一边遍历一边生成邻居节点,就可以同时更新 neighbors
了。
同样需要一个 map
记录已经生成的节点。
public Node cloneGraph(Node node) { if (node == null) { return node; } Queue<Node> queue = new LinkedList<>(); Map<Integer, Node> map = new HashMap<>(); queue.offer(node); //先生成第一个节点 Node n = new Node(); n.val = node.val; n.neighbors = new ArrayList<Node>(); map.put(n.val, n); while (!queue.isEmpty()) { Node cur = queue.poll(); for (Node temp : cur.neighbors) { //没有生成的节点就生成 if (!map.containsKey(temp.val)) { n = new Node(); n.val = temp.val; n.neighbors = new ArrayList<Node>(); map.put(n.val, n); queue.offer(temp); } map.get(cur.val).neighbors.add(map.get(temp.val)); } } return map.get(node.val); }
解法二 DFS
DFS
的话用递归即可,也用一个 map
记录已经生成的节点。
public Node cloneGraph(Node node) { if (node == null) { return node; } Map<Integer, Node> map = new HashMap<>(); return cloneGrapthHelper(node, map); } private Node cloneGrapthHelper(Node node, Map<Integer, Node> map) { if (map.containsKey(node.val)) { return map.get(node.val); } //生成当前节点 Node n = new Node(); n.val = node.val; n.neighbors = new ArrayList<Node>(); map.put(node.val, n); //添加它的所有邻居节点 for (Node temp : node.neighbors) { n.neighbors.add(cloneGrapthHelper(temp, map)); } return n; }
总
这道题本质上就是对图的遍历,只要想到用 map
去存储已经生成的节点,题目基本上就解决了。