[leetcod] Clone Graph

本文介绍如何使用深度优先搜索(DFS)和广度优先搜索(BFS)来遍历图,并通过实例详细解释如何利用这两种方法克隆无向图。同时对比了DFS与BFS的不同之处,提供了递归和非递归两种DFS实现方式。

题目

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
         / \
         \_/


题解:
引用:http://www.cnblogs.com/springfor/p/3874591.html
这道题考察对图的遍历和利用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
1   procedure DFS(G,v):
2       label v as discovered
3       for all edges from v to w in G.adjacentEdges(v) do
4           if vertex w is not labeled as discovered then
5               recursively call DFS(G,w)
非递归写法的DFS伪代码如下:
Input: A graph G and a root v of G
复制代码
1   procedure DFS-iterative(G,v):
2       let S be a stack
3       S.push(v)
4       while S is not empty
5             v ← S.pop() 
6             if v is not labeled as discovered:
7                 label v as discovered
8                 for all edges from v to w in G.adjacentEdges(v) do
9                     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
10         end if
11         for all edges e in G.adjacentEdges(t) loop
12            u ← G.adjacentVertex(t,e)
13            if u is not in V then
14                add u to V
15                enqueue u onto Q
16            end if
17         end loop
18      end loop
19      return none
20  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);
10         
11         while(!queue.isEmpty()){
12             UndirectedGraphNode curnode = queue.poll();
13             for(UndirectedGraphNode aneighbor: curnode.neighbors){//check each neighbor
14                 if(!hm.containsKey(aneighbor)){//if not visited,then add to queue
15                     queue.add(aneighbor);
16                     UndirectedGraphNode newneighbor = new UndirectedGraphNode(aneighbor.label);
17                     hm.put(aneighbor, newneighbor);
18                 }
19                 
20                 hm.get(curnode).neighbors.add(hm.get(aneighbor));
21             }
22         }
23         
24         return head;
25     }
复制代码
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
10         return head;
11     }
12     public void DFS(HashMap<UndirectedGraphNode, UndirectedGraphNode> hm, UndirectedGraphNode node){
13         if(node == null)
14             return;
15             
16         for(UndirectedGraphNode aneighbor: node.neighbors){ 
17             if(!hm.containsKey(aneighbor)){
18                 UndirectedGraphNode newneighbor = new UndirectedGraphNode(aneighbor.label);
19                 hm.put(aneighbor, newneighbor);
20                 DFS(hm, aneighbor);//DFS
21             }
22             hm.get(node).neighbors.add(hm.get(aneighbor));
23         }
24     }
复制代码


下面一种方法是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);
10         
11         while(!stack.isEmpty()){
12             UndirectedGraphNode curnode = stack.pop();
13             for(UndirectedGraphNode aneighbor: curnode.neighbors){//check each neighbor
14                 if(!hm.containsKey(aneighbor)){//if not visited,then push to stack
15                     stack.push(aneighbor);
16                     UndirectedGraphNode newneighbor = new UndirectedGraphNode(aneighbor.label);
17                     hm.put(aneighbor, newneighbor);
18                 }
19                 
20                 hm.get(curnode).neighbors.add(hm.get(aneighbor));
21             }
22         }
23         
24         return head;
25     }
复制代码

 

转载于:https://www.cnblogs.com/fengmangZoo/p/4192777.html

<think>好的,用户想要使用conda create命令通过--clone参数从现有的bev环境克隆生成新环境graph。我需要先确认conda克隆环境的基本语法。记得conda的克隆命令结构应该是conda create --name 新环境名 --clone 原环境名。所以具体到这里,应该是conda create --name graph --clone bev。 接下来,用户可能遇到的问题可能包括环境名称是否正确,或者权限问题。比如,如果用户没有权限写入conda的环境目录,可能会报错。这时候可能需要使用sudo,但通常不推荐,最好在用户有权限的目录下操作。另外,还需要确认原环境bev确实存在,用户可能拼写错误环境名。如果不存在,会提示找不到环境。 另外,用户提到的引用中有提到conda create报错的解决办法,比如修改.condarc文件使用清华镜像源。如果在克隆过程中出现网络问题,可能需要检查conda的配置,确保源设置正确,避免下载包时失败。例如,用户可能在克隆时,conda会尝试安装某些包,如果源不可达,就会出错,这时候可以参考引用[3]中的方法,配置镜像源。 还有,用户可能是在克隆环境时遇到空间不足的问题,这时候需要确保磁盘有足够的空间存放新环境。克隆环境实际上是在conda的envs目录下复制一份原环境,所以需要足够的存储空间。 另外,用户可能想知道克隆完成后如何激活新环境,使用conda activate graph。如果激活失败,可能需要初始化conda的shell,比如运行conda init bash(假设用户使用bash),或者重新打开终端。 总结步骤应该是: 1. 检查bev环境是否存在:conda env list 2. 执行克隆命令:conda create --name graph --clone bev 3. 如果遇到权限问题,可能需要使用管理员权限或者调整目录权限。 4. 如果遇到网络问题,配置镜像源。 5. 激活新环境测试:conda activate graph 6. 确认环境中的包是否正确复制。 同时,根据引用[3],如果遇到创建环境的问题,可能需要调整conda的配置文件,比如使用清华的镜像源来加快下载速度或者避免某些包无法下载的问题。用户之前可能遇到过类似的问题,所以需要提醒他们检查这些配置,特别是在克隆过程中如果有需要下载额外包的话。</think>### 分步解答 要使用 `conda create` 命令通过 `--clone` 参数从现有环境 `bev` 克隆生成新环境 `graph`,步骤如下: 1. **确认现有环境存在** 首先确保 `bev` 环境已正确安装并存在于 Conda 环境列表中。可通过以下命令查看环境列表: ```bash conda env list ``` 若列表中包含 `bev`,则继续下一步;若不存在,需先创建或修复原环境。 2. **执行克隆命令** 使用 `conda create` 的 `--clone` 参数克隆环境: ```bash conda create --name graph --clone bev ``` 此命令会复制 `bev` 环境的所有依赖项到新环境 `graph` 中[^1]。 3. **解决潜在问题** - **权限问题**:若提示权限不足,尝试在命令前添加 `sudo`(需谨慎,建议优先确保用户对 Conda 目录有写入权限)。 - **网络问题**:若克隆过程中因依赖下载失败报错,可参考引用[3]修改 `~/.condarc` 文件,使用清华镜像源加速下载[^3]。 4. **验证新环境** 克隆完成后,激活并验证新环境: ```bash conda activate graph conda list # 检查包列表是否 bev 一致 ``` --- ### 相关问题 1. 如何彻底删除一个 Conda 环境? 2. Conda 克隆环境和手动复制环境目录有什么区别? 3. 克隆环境时出现 `PackagesNotFoundError` 如何解决? : 引用[1]:搭建环境,直接无脑follow 官方的INSTALL.md。 : 引用[3]:conda create -n 环境报错解决办法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值