题目

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
/ \
\_/ 题解:
这道题考察对图的遍历和利用HashMap拷贝的方法。
对图的遍历就是两个经典的方法DFS和BFS。BFS经常用Queue实现,DFS经常用递归实现(可改为栈实现)。
拷贝方法是用用HashMap,key存原始值,value存copy的值,用DFS,BFS方法遍历帮助拷贝neighbors的值。 先复习下DFS和BFS。 DFS(Dpeth-first Search)
顾名思义,就是深度搜索,一条路走到黑,再选新的路。
记得上Algorithm的时候,教授举得例子就是说,DFS很像好奇的小孩,你给这个小孩几个盒子套盒子,好奇的小孩肯定会一个盒子打开后继续再在这个盒子里面搜索。
等把这一套盒子都打开完,再打开第二套的。
Wikipedia上的讲解是:“Depth-first search (DFS) is an algorithm for traversing or searching tree or graph data structures.
One starts at the root (selecting some arbitrary node as the root in the case of a graph) and explores as far as possible
along each branch before backtracking.”
通常来说简便的DFS写法是用递归,如果非递归的话就是栈套迭代,思想是一样的。
递归写法的DFS伪代码如下:
Input: A graph G and a root v of G
   procedure DFS(G,v):
       label v as discovered
       for all edges from v to w in G.adjacentEdges(v) do
           if vertex w is not labeled as discovered then
               recursively call DFS(G,w)
非递归写法的DFS伪代码如下:
Input: A graph G and a root v of G
   procedure DFS-iterative(G,v):
       let S be a stack
       S.push(v)
       while S is not empty
             v ← S.pop() 
             if v is not labeled as discovered:
                 label v as discovered
                 for all edges from v to w in G.adjacentEdges(v) do
                     S.push(w)

BFS(Breadth-first Search)
这个就是相对于BFS的另外一种对图的遍历方法,对于一个节点来说先把所有neighbors都检查一遍,再从第一个neighbor开始,循环往复。
由于BFS的这个特质,BFS可以帮助寻找最短路径。
Wikipedia上面对BFS的定义是:
“In graph theory, breadth-first search (BFS) is a strategy for searching in a graph
when search is limited to essentially two operations: (a) visit and
inspect a node of a graph; (b) gain access to visit the nodes that
neighbor the currently visited node. The BFS begins at a root node and
inspects all the neighboring nodes. Then for each of those neighbor
nodes in turn, it inspects their neighbor nodes which were unvisited,
and so on. Compare BFS with the equivalent, but more memory-efficient
Iterative deepening depth-first search and contrast with depth-first search.” 通常BFS用queue+循环实现,伪代码如下:
Input: A graph G and a root v of G
 1   procedure BFS(G,v) is
 2       create a queue Q
 3       create a set V
 4       add v to V
 5       enqueue v onto Q
 6       while Q is not empty loop
 7          t ← Q.dequeue()
 8          if t is what we are looking for then
 9             return t
         end if
         for all edges e in G.adjacentEdges(t) loop
            u ← G.adjacentVertex(t,e)
            if u is not in V then
                add u to V
                enqueue u onto Q
            end if
         end loop
      end loop
      return none
  end BFS
********************************************************************************************************************************
下面就是这道题的3种解题方法。 第一种实现方法是BFS的,就是先将头节点入queue,每一次queue出列一个node,然后检查这个node的所有的neighbors,如果没visited过,就入队,并更新neighbor。
然后更新新的neighbor列表。
代码如下:
 1     public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
 2         if(node == null)
 3             return null;
 4             
 5         HashMap<UndirectedGraphNode, UndirectedGraphNode> hm = new HashMap<UndirectedGraphNode, UndirectedGraphNode>();
 6         LinkedList<UndirectedGraphNode> queue = new LinkedList<UndirectedGraphNode>();
 7         UndirectedGraphNode head = new UndirectedGraphNode(node.label);
 8         hm.put(node, head);
 9         queue.add(node);
         
         while(!queue.isEmpty()){
             UndirectedGraphNode curnode = queue.poll();
             for(UndirectedGraphNode aneighbor: curnode.neighbors){//check each neighbor
                 if(!hm.containsKey(aneighbor)){//if not visited,then add to queue
                     queue.add(aneighbor);
                     UndirectedGraphNode newneighbor = new UndirectedGraphNode(aneighbor.label);
                     hm.put(aneighbor, newneighbor);
                 }
                 
                 hm.get(curnode).neighbors.add(hm.get(aneighbor));
             }
         }
         
         return head;
     }
DFS的递归操作如下,迭代复制neighbors:
 1     public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
 2         if(node == null)
 3             return null;
 4             
 5         HashMap<UndirectedGraphNode, UndirectedGraphNode> hm = new HashMap<UndirectedGraphNode, UndirectedGraphNode>();
 6         UndirectedGraphNode head = new UndirectedGraphNode(node.label);
 7         hm.put(node, head);
 8         
 9         DFS(hm, node);//DFS
         return head;
     }
     public void DFS(HashMap<UndirectedGraphNode, UndirectedGraphNode> hm, UndirectedGraphNode node){
         if(node == null)
             return;
             
         for(UndirectedGraphNode aneighbor: node.neighbors){ 
             if(!hm.containsKey(aneighbor)){
                 UndirectedGraphNode newneighbor = new UndirectedGraphNode(aneighbor.label);
                 hm.put(aneighbor, newneighbor);
                 DFS(hm, aneighbor);//DFS
             }
             hm.get(node).neighbors.add(hm.get(aneighbor));
         }
     }

下面一种方法是DFS的非递归方法,中点是把BFS中的queue换成stack,因为出列方法不一样了,所以遍历的线路就不一样了。代码如下:
 1     public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
 2         if(node == null)
 3             return null;
 4             
 5         HashMap<UndirectedGraphNode, UndirectedGraphNode> hm = new HashMap<UndirectedGraphNode, UndirectedGraphNode>();
 6         LinkedList<UndirectedGraphNode> stack = new LinkedList<UndirectedGraphNode>();
 7         UndirectedGraphNode head = new UndirectedGraphNode(node.label);
 8         hm.put(node, head);
 9         stack.push(node);
         
         while(!stack.isEmpty()){
             UndirectedGraphNode curnode = stack.pop();
             for(UndirectedGraphNode aneighbor: curnode.neighbors){//check each neighbor
                 if(!hm.containsKey(aneighbor)){//if not visited,then push to stack
                     stack.push(aneighbor);
                     UndirectedGraphNode newneighbor = new UndirectedGraphNode(aneighbor.label);
                     hm.put(aneighbor, newneighbor);
                 }
                 
                 hm.get(curnode).neighbors.add(hm.get(aneighbor));
             }
         }
         
         return head;
     }
												

Clone Graph leetcode java(DFS and BFS 基础)的更多相关文章

  1. Clone Graph [LeetCode]

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

  2. Clone Graph——LeetCode

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

  3. 【万能的DFS和BFS基础框架】-多刷题才是硬道理!

  4. leetcode 133. Clone Graph ----- java

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

  5. Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph)

    Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree ...

  6. [LeetCode] 133. Clone Graph 克隆无向图

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

  7. LeetCode: Clone Graph 解题报告

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

  8. [Leetcode Week3]Clone Graph

    Clone Graph题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/clone-graph/description/ Description Clon ...

  9. 【LeetCode】133. Clone Graph 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 DFS BFS 日期 题目地址:https://le ...

随机推荐

  1. AngularJS Directive 隔离 Scope 数据交互

    什么是隔离 Scope AngularJS 的 directive 默认能共享父 scope 中定义的属性,例如在模版中直接使用父 scope 中的对象和属性.通常使用这种直接共享的方式可以实现一些简 ...

  2. 基于 AVPlayer 自定义播放器

    如果我只是简单的播放一个视频,而不需要考虑播放器的界面.iOS9.0 之前使用 MPMoviePlayerController, 或者内部自带一个 view 的 MPMoviePlayerViewCo ...

  3. JNI笔记1

    一.什么是JNI Java Native Interface(JNI)是Java语言的本地编程接口 是 Java 与操作系统本地代码互相调用的功能的接口 二.Java 调用C/C++步骤: 1.在Ja ...

  4. GCD

    Grand Central Dispatch(GCD)包含语言特点.运行库和系统增强功能,它提供系统的.综合的改进,进而去支持并发代码在iOS和OSX多核硬件上的执行. 子系统.CoreFoundat ...

  5. Struts2 - Conversion Plugin

    转载:http://www.cnblogs.com/ikuman/archive/2013/11/04/3403073.html 1.struts2自2.1以后推荐使用Convention Plugi ...

  6. CLR垃圾回收的设计

    作者: Maoni Stephens (@maoni0) - 2015 附: 关于垃圾回收的信息,可以参照本文末尾资源章节里引用的垃圾回收手册一书. 组件架构 GC包含的两个组件分别是内存分配器和垃圾 ...

  7. Oracle如何实现创建数据库、备份数据库及数据导出导入的一条龙操作

    Oracle中对数据对象和数据的管理,无疑都是使用PL/SQL Developer来进行管理,该工具也提供给我们很多方便.快捷的操作,使得我们不再为Oracle本身丑陋.难用的UI而抱怨.由于我们一般 ...

  8. Linq专题之提高编码效率—— 第一篇 Aggregate方法

    我们知道linq是一个很古老的东西,大家也知道,自从用了linq,我们的foreach少了很多,但有一个现实就是我们在实际应用中使用到的却是屈指可数 的几个方法,这个系列我会带领大家看遍linq,好的 ...

  9. 从零自学Hadoop(06):集群搭建

    阅读目录 序 集群搭建 监控 系列索引 本文版权归mephisto和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作. 文章是哥(mephisto)写的,SourceLink 序 上一 ...

  10. SQL数据库修改默认备份和恢复路径

    每次都做数据恢复和备份的时候,点Add文件,系统会自动指定到一个默认路径,是SQL的安装目录,但是我的数据库不是备份在这里,每次都要更改有点麻烦. 如上图,更改这个有三个方法. 方法一:找到注册表,手 ...