LeetCode 133:克隆图 Clone Graph
题目:
给定无向连通图中一个节点的引用,返回该图的深拷贝(克隆)。图中的每个节点都包含它的值 val
(Int
) 和其邻居的列表(list[Node]
)。
Given a reference of a node in a connected undirected graph, return a deep copy (clone) of the graph. Each node in the graph contains a val (int
) and a list (List[Node]
) of its neighbors.
示例:
输入:
{"$id":"1","neighbors":[{"$id":"2","neighbors":[{"$ref":"1"},{"$id":"3","neighbors":[{"$ref":"2"},{"$id":"4","neighbors":[{"$ref":"3"},{"$ref":"1"}],"val":4}],"val":3}],"val":2},{"$ref":"4"}],"val":1}
解释:
节点 1 的值是 1,它有两个邻居:节点 2 和 4 。
节点 2 的值是 2,它有两个邻居:节点 1 和 3 。
节点 3 的值是 3,它有两个邻居:节点 2 和 4 。
节点 4 的值是 4,它有两个邻居:节点 1 和 3 。
提示:
- 节点数介于 1 到 100 之间。
- 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
- 由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
- 必须将给定节点的拷贝作为对克隆图的引用返回。
Note:
- The number of nodes will be between 1 and 100.
- The undirected graph is a simple graph, which means no repeated edges and no self-loops in the graph.
- Since the graph is undirected, if node p has node q as neighbor, then node q must have node p as neighbor too.
- You must return the copy of the given node as a reference to the cloned graph.
解题思路:
涉及到图的遍历无非就是DFS(深度优先搜索)、BFS(广度优先搜索),可以先看前几日的这篇文章:
BFS就需要借助队列实现,DFS可以借助栈也可以直接用递归实现。就这道题而言直接用递归更好一些,无需开辟额外的数据结构空间记录节点。BFS、DFS写法相对固定,建议花点时间一次性理解透,一劳永逸。
这道题思路很清晰,关键点是如何深拷贝随机节点,可以参考链表的这篇文章:LeetCode 138:复制带随机指针的链表 Copy List with Random Pointer
链表是线性的,可以 复制节点到每个节点之后,很巧妙的完成深拷贝。显然图这样的树状结构无法用这种方法,只能借助数据结构记录已拷贝过的节点。这种需要映射新旧节点关系自然就是用散列表(字典)。
Java:
class Solution {
public Node cloneGraph(Node node) {
if (node == null) return node;
Queue<Node> queue = new LinkedList<>();//借助队列实现BFS
Map<Node, Node> map = new HashMap<>();//哈希映射
Node head = new Node(node.val, new ArrayList<>());//头节点
map.put(node, head);//哈希映射原节点和新节点
queue.add(node);//原节点加入到队列
while (!queue.isEmpty()) {//队列不为空就重复循环
Node tmp = queue.poll();//弹出队列头节点
for (Node n : tmp.neighbors) {//遍历邻居节点
if (!map.containsKey(n)) {//字典的键不包含该节点时
map.put(n, new Node(n.val, new ArrayList<>()));//新建映射关系加入字典
queue.add(n);//加入队列
}
map.get(tmp).neighbors.add(map.get(n));//加入邻居节点
}
}
return head;
}
}
Python3:
class Solution:
def cloneGraph(self, node: 'Node') -> 'Node':
if not node: return node
head = Node(node.val, [])#头节点
map = {node: head}#初始化字典,并建立新旧节点的映射关系
queue = collections.deque()#队列
queue.append(node)#原节点加入队列
while queue:#队列不为空
tmp = queue.popleft()#弹出队列头节点
for n in tmp.neighbors:#遍历邻居节点
if n in map.keys():#n节点存在于字典的键里时
map[tmp].neighbors.append(map[n])#直接加入到新节点的邻居节点
else:
map[n] = Node(n.val, [])#新建节点并建立映射关系
map[tmp].neighbors.append(map[n])#由新建的映射关系取出节点并加入邻居节点
queue.append(n)#该邻居节点加入队列
return head
DFS:
递归完成的深度优先搜索非常简洁,比较容易理解,唯一要注意的就是需要把字典定义在函数外。
Java:
class Solution {
Map<Node, Node> map = new HashMap();
public Node cloneGraph(Node node) {
if (node == null) return node;
map.put(node, new Node(node.val, new ArrayList<>()));//每次都要新建节点并建立映射关系
for (Node n : node.neighbors) {
if (map.containsKey(n)) map.get(node).neighbors.add(map.get(n));
else map.get(node).neighbors.add(cloneGraph(n));
}
return map.get(node);
}
}
Python3:
class Solution:
map = dict()
def cloneGraph(self, node: 'Node') -> 'Node':
if not node: return node
self.map[node] = Node(node.val, [])
for n in node.neighbors:
if n in self.map.keys():
self.map[node].neighbors.append(self.map[n])
else:
self.map[node].neighbors.append(self.cloneGraph(n))
return self.map[node]
注意:
python中的字典取values时可以 dict().get(key)
也可以 dict[key]
时间复杂度都为1,但是在做算法题时肯定要用 dict[key]
这种方式。因为 get() 方法虽然效果一样,但是反复调用函数造成的时间消耗非常高,python语言本来就慢,应该养成尽可能优化代码的习惯。
欢迎关注微.信公.众号:爱写Bug
LeetCode 133:克隆图 Clone Graph的更多相关文章
- 133克隆图 · Clone Graph
[抄题]: 克隆一张无向图,图中的每个节点包含一个 label 和一个列表 neighbors. [思维问题]: [一句话思路]: 先BFS克隆点(一个点+扩展所有邻居),再克隆邻居(一个点+扩展所有 ...
- Java实现 LeetCode 133 克隆图
133. 克隆图 给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆). 图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node]). class Node { ...
- Leetcode 133.克隆图
克隆图 克隆一张无向图,图中的每个节点包含一个 label (标签)和一个 neighbors (邻接点)列表 . OJ的无向图序列化: 节点被唯一标记. 我们用 # 作为每个节点的分隔符,用 , 作 ...
- [Java]LeetCode133. 克隆图 | Clone Graph
Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. OJ's ...
- 【leetcode 133. 克隆图】解题报告
方法一:dfs(递归) map<Node*,Node*> dict; Node* clone(Node* node) { if (!node) return node; if (dict. ...
- Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph)
Leetcode之广度优先搜索(BFS)专题-133. 克隆图(Clone Graph) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tree ...
- 【LeetCode】133. 克隆图
133. 克隆图 知识点:图:递归;BFS 题目描述 给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆). 图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[No ...
- 【LeetCode】克隆图
[问题]给定无向连通图中一个节点的引用,返回该图的深拷贝(克隆).图中的每个节点都包含它的值 val(Int) 和其邻居的列表(list[Node]). 解释: 节点 的值是 ,它有两个邻居:节点 和 ...
- C#LeetCode刷题-图
图篇 # 题名 刷题 通过率 难度 133 克隆图 18.7% 中等 207 课程表 40.0% 中等 210 课程表 II 40.0% 中等 310 最小高度树 29.5% 中等 3 ...
随机推荐
- PHP面试题大全(值得收藏)
PHP进阶.面试:文档.视频资源点击免费获取 一 .PHP基础部分 1.PHP语言的一大优势是跨平台,什么是跨平台? PHP的运行环境最优搭配为Apache+MySQL+PHP,此运行环境可以在不同操 ...
- 【MySQL报错】ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement
ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot exec ...
- JDBC进阶 元数据
1:resultSet 1.1最基本的ResultSet. 1.2 可滚动的ResultSet类型 1.3 可更新的ResultSet 1.4 可保持的ResultSet 2:PrepareState ...
- 使用configparser模块进行封装,构造配置文件处理器
from configparser import ConfigParser class HandleConfig: ''' 定义一个配置文件处理类 ''' def __init__(self, fil ...
- jsp页面科学计数法显示问题的解决办法
在JSP页面中返回的double类型的数值,如果数值过大,就会被显示成科学计数法. 这个问题通常出现在表单填写的input中,因此是必须要解决的问题. JSTL提供了标准的数值格式化标签,使用上非常简 ...
- docker registry 删除镜像 垃圾回收
操作步骤 通过环境变量修改默认配置,允许删除 获取image的sha值 进入registry容器中,执行垃圾回收 删除残留目录 #环境变量 REGISTRY_STORAGE_DELETE_ENABLE ...
- FtpClient上传文件速度非常慢,而且大小为0,上传失败
问题发生: 环境:VSFTP+FTPClient+Client 使用FTPClient上传文件的时候总是卡住,而且文件大小为0,上传失败, 解决方案: 添加代码:调用FTPClient的enterLo ...
- JQ中的Ajax的封装
1.认识JQ中ajax的封装 jQ 对于ajax的封装有两层实现:$.ajax 为底层封装实现:基于 $.ajax ,分别实现了$.get 与$.post 的高层封装实现: 2.Ajax的底 ...
- django支付宝支付集成
概要 本文是关于django集成支付宝[电脑网站支付]功能的过程记录. 功能逻辑主要分为两块: 用户下单跳转至支付宝支付界面 支付成功的回调验证 本文用到的alipay-sdk是基于阿里开发文档htt ...
- 【LeetCode】650. 只有两个键的键盘
只有两个键的键盘 最初在一个记事本上只有一个字符 'A'.你每次可以对这个记事本进行两种操作: 1.Copy All (复制全部) : 你可以复制这个记事本中的所有字符(部分的复制是不允许的). 2. ...