一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情。
一、题目
leetcode 克隆图
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 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 的邻居。
图是连通图,你可以从给定节点访问到所有节点。
二、题解
就是说要复制一个联通的链表节点,不是复制节点的引用,而是要完全new出一个节点。
方法一 由于需要复制出一个同样的图节点,所以我们需要遍历该图,遍历过程中构造新图的节点。给定的图为无向联通图,给任意节点都一样,每个节点包含本节点的值,以及其邻居节点的集合。同时每一个节点值与节点的索引相同,例如[1->2->3->4]四个节点,第一个节点为1,其邻居节点为2和4;第二个节点为2,其邻居节点为1和3;第三个节点为3,其邻居节点为2和4;第四个节点为4,其邻居节点为1和3。那么我们可以用DFS深度优先搜索来遍历图节点,以给定的节点开始,如果当前节点为空,就返回空节点,否则构造一个值相同的新节点以及空的邻居集合,然后获取当前节点的邻居节点,最后再以邻居节点开始获取其邻居节点,将邻居节点构造出的节点添加到当前节点的邻居集合中,重复这个过程直到遍历完所有节点。因为需要遍历邻居节点,可以发现某些邻居节点可能之前已经遍历过了,所以需要记录下已经遍历过的节点,如果已经遍历过则不需要新创建节点,直接使用之前创建的。所以我们需要一个节点哈希集合存储已经遍历构造出的新节点,如果遍历的节点存在哈希表中则不需要重新构造。
方法二 同样也可以BFS广度优先搜索来遍历,同时也需要哈希表记录已经遍历的节点,以及一个队列辅助遍历。首先构造出一个同样值的新节点,然后往哈希表中记录下这个节点,然后再将节点加入队列,遍历队列元素节点,然后也遍历其邻居节点,如果其邻居节点没有遍历过(哈希表中不存在)那么就构造出同样的节点,加入哈希表以及队列中,最后将遍历的邻居节点添加到遍历队列节点的邻居集合中。最后遍历完成返回构造的新节点即可。
三、代码
方法一 Java代码
class Solution {
Map<Node, Node> cloneMap = new HashMap<>();
public Node cloneGraph(Node node) {
if (node == null) {
return null;
}
if (cloneMap.containsKey(node)) {
return cloneMap.get(node);
}
Node cloneNode = new Node(node.val, new ArrayList<>());
cloneMap.put(node, cloneNode);
for (Node neighbor : node.neighbors) {
cloneNode.neighbors.add(cloneGraph(neighbor));
}
return cloneNode;
}
}
时间复杂度:O(n),需要遍历图的每一个节点,
空间复杂度:O(n),需要一个哈希表记录以及遍历的节点,以及构造新图节点空间,和递归消耗的栈空间。
方法二 Java代码
class Solution {
public Node cloneGraph(Node node) {
if (node == null) {
return null;
}
Node cloneNode = new Node(node.val, new ArrayList<>());
Map<Node, Node> cloneMap = new HashMap<>();
cloneMap.put(node, cloneNode);
Deque<Node> deque = new LinkedList<>();
deque.offer(node);
while (!deque.isEmpty()) {
Node curNode = deque.poll();
for (Node neighbor : curNode.neighbors) {
if (!cloneMap.containsKey(neighbor)) {
cloneMap.put(neighbor, new Node(neighbor.val, new ArrayList<>()));
deque.offer(neighbor);
}
cloneMap.get(curNode).neighbors.add(cloneMap.get(neighbor));
}
}
return cloneNode;
}
}
时间复杂度:O(n),需要遍历图的每一个节点,
空间复杂度:O(n),需要一个哈希表记录以及遍历的节点,以及构造新图节点空间,和一个队列辅助遍历。