文章目录
- 克隆图
- 思路一
克隆图
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。class Node {public int val;public List<Node> neighbors; }
测试用例格式:
简单起见,每个节点的值都和它的索引相同。例如,第一个节点值为 1(val = 1),第二个节点值为 2(val = 2),以此类推。该图在测试用例中使用邻接列表表示。
邻接列表 是用于表示有限图的无序列表的集合。每个列表都描述了图中节点的邻居集。
给定节点将始终是图中的第一个节点(值为 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 = []
输出:[]
解释:这个图是空的,它不含任何节点。
思路一
var cloneGraph = function(node) {if (node === null) return null;const visited = new Map();function dfs(originalNode) {if (visited.has(originalNode)) {return visited.get(originalNode);}const cloneNode = new Node(originalNode.val, []);visited.set(originalNode, cloneNode);for (const neighbor of originalNode.neighbors) {cloneNode.neighbors.push(dfs(neighbor));}return cloneNode;}return dfs(node);
};
讲解
使用深度优先搜索(DFS)来解决图的克隆问题。其主要思路是递归地遍历图中的每个节点,并在遍历过程中创建节点的克隆版本。为了避免重复克隆相同的节点,使用了一个 Map 结构 visited 来存储已经克隆过的节点,以节点的引用为键,克隆后的节点为值。
- 初始化:创建一个 Map 叫做 visited,用于存储已经克隆过的节点。如果图中存在循环,或者有多个节点指向同一个节点,这个 Map 可以防止无限循环和重复克隆。
- 定义 DFS 函数:dfs(originalNode) 函数负责克隆 originalNode 及其所有邻居节点。
- 检查是否已克隆:在 dfs 函数内部,首先检查 originalNode 是否已经在 visited 中。如果是,直接返回对应的克隆节点,避免重复工作。
- 创建克隆节点:如果 originalNode 尚未被克隆,创建一个新的 Node 实例,将其值设置为 originalNode.val,并将邻居列表初始化为空数组。
- 存储克隆节点:将 originalNode 和其克隆版本的映射存储在 visited 中。
- 克隆邻居:遍历 originalNode 的所有邻居,对每个邻居调用 dfs 函数来获取其克隆版本,并将这些克隆版本添加到当前克隆节点的邻居列表中。
- 返回克隆节点:最后,dfs 函数返回当前克隆节点的引用。
- 启动克隆过程:在 cloneGraph 函数外部,调用 dfs(node) 来开始克隆过程。node 是要克隆的图的起始节点。
关键点:
● 使用 Map 来跟踪已经克隆的节点,防止重复克隆和无限循环。
隆。
● 每个克隆节点的邻居列表是在克隆过程中动态构建的,确保了克隆图的结构与原图完全一致。
这种方法的时间复杂度为 O(V+E),其中 V 是节点数,E 是边数。这是因为每个节点和每条边都会被访问一次。空间复杂度也为 O(V+E),主要是由于递归调用栈和 visited Map 的使用。