克隆图
难度:
标签:
题目描述
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val
(int
) 和其邻居的列表(list[Node]
)。
class Node { public int val; public List<Node> neighbors; }
测试用例格式:
简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1(val = 1
),第二个节点值为 2(val = 2
),以此类推。该图在测试用例中使用邻接列表表示。
邻接列表 是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
给定节点将始终是图中的第一个节点(值为 1)。你必须将 给定节点的拷贝 作为对克隆图的引用返回。
示例 1:
输入:adjList = [[2,4],[1,3],[2,4],[1,3]] 输出:[[2,4],[1,3],[2,4],[1,3]] 解释: 图中有 4 个节点。 节点 1 的值是 1,它有两个邻居:节点 2 和 4 。 节点 2 的值是 2,它有两个邻居:节点 1 和 3 。 节点 3 的值是 3,它有两个邻居:节点 2 和 4 。 节点 4 的值是 4,它有两个邻居:节点 1 和 3 。
示例 2:
输入:adjList = [[]] 输出:[[]] 解释:输入包含一个空列表。该图仅仅只有一个值为 1 的节点,它没有任何邻居。
示例 3:
输入:adjList = [] 输出:[] 解释:这个图是空的,它不含任何节点。
示例 4:
输入:adjList = [[2],[1]] 输出:[[2],[1]]
提示:
- 节点数不超过 100 。
- 每个节点值
Node.val
都是唯一的,1 <= Node.val <= 100
。 - 无向图是一个简单图,这意味着图中没有重复的边,也没有自环。
- 由于图是无向的,如果节点 p 是节点 q 的邻居,那么节点 q 也必须是节点 p 的邻居。
- 图是连通图,你可以从给定节点访问到所有节点。
代码结果
运行时间: 23 ms, 内存: 16.4 MB
/*
* Problem Description:
* You are given a reference of a node in a connected undirected graph,
* and you need to return a deep copy (clone) of the graph.
* Each node contains a value (int) and a list of its neighbors.
* The graph is represented as an adjacency list in the test cases.
*/
import java.util.*;
import java.util.stream.*;
class Node {
public int val;
public List<Node> neighbors;
public Node(int val) {
this.val = val;
this.neighbors = new ArrayList<>();
}
}
public class Solution {
// HashMap to store the mapping from original node to its clone
private Map<Node, Node> visited = new HashMap<>();
// Method to clone the graph using Java Stream
public Node cloneGraph(Node node) {
if (node == null) return null;
// If the node is already cloned, return the clone
if (visited.containsKey(node)) return visited.get(node);
// Create a new node for the clone
Node cloneNode = new Node(node.val);
// Store the clone in the visited map
visited.put(node, cloneNode);
// Clone neighbors using Stream API
cloneNode.neighbors = node.neighbors.stream()
.map(this::cloneGraph)
.collect(Collectors.toList());
return cloneNode;
}
}
解释
方法:
这个题解使用了广度优先搜索(BFS)的思路来克隆图。首先判断给定的节点是否为空,如果为空则直接返回None。然后使用一个字典records来记录原始节点和克隆节点之间的映射关系,避免重复创建节点。定义一个辅助函数get_new_node(u),用于根据原始节点u创建对应的克隆节点,并将其存储在records中。接下来,从给定的节点开始进行BFS遍历,使用一个队列q存储待遍历的节点,并用一个布尔数组visited标记节点是否已被访问过。在BFS的过程中,对于每个遍历到的节点u,通过get_new_node(u)获取其对应的克隆节点new_u,然后遍历u的所有邻居节点v,通过get_new_node(v)获取v的克隆节点并将其添加到new_u的邻居列表中。如果v尚未被访问过,则将其标记为已访问,并将其加入队列q中等待遍历。最后,返回给定节点对应的克隆节点作为结果。
时间复杂度:
O(n+m),最坏情况下为O(n^2)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在开始BFS之前需要检查给定节点是否为空?
▷🦆
在get_new_node函数中,为什么选择使用节点的值作为字典records的键,而不是使用节点对象本身?
▷🦆
在BFS过程中,每个节点的所有邻居都被添加到克隆节点的邻居列表中,这个过程是否保证了邻居之间的正确连接关系,即原图中的任意两个相邻节点在克隆图中也相邻?
▷🦆
visited数组的大小固定为101,这是否意味着解决方案只适用于节点数量不超过100的图?如果是,该如何修改代码以支持更大的图?
▷相关问题
随机链表的复制
给你一个长度为 n
的链表,每个节点包含一个额外增加的随机指针 random
,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n
个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next
指针和 random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X
和 Y
两个节点,其中 X.random --> Y
。那么在复制链表中对应的两个节点 x
和 y
,同样有 x.random --> y
。
返回复制链表的头节点。
用一个由 n
个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index]
表示:
val
:一个表示Node.val
的整数。random_index
:随机指针指向的节点索引(范围从0
到n-1
);如果不指向任何节点,则为null
。
你的代码 只 接受原链表的头节点 head
作为传入参数。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]] 输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]] 输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]] 输出:[[3,null],[3,0],[3,null]]
提示:
0 <= n <= 1000
-104 <= Node.val <= 104
Node.random
为null
或指向链表中的节点。