133. 克隆图

题目描述:

给你无向 连通 🔗 图中一个节点的引用,请你返回该图的 深拷贝 🔗(克隆)。

图中的每个节点都包含它的值 valint) 和其邻居的列表( 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 = []
输出:[]
解释:这个图是空的,它不含任何节点。

提示:

  • 这张图中的节点数在 [0, 100] 之间。
  • 1 <= Node.val <= 100
  • 每个节点值 Node.val 都是唯一的,
  • 图中没有重复的边,也没有自环。
  • 图是连通图,你可以从给定节点访问到所有节点。

解题分析及思路:

方法:深度优先搜索(DFS)+ 哈希表映射

思路:

克隆图的核心挑战是:

  1. 确保每个节点只被克隆一次(避免重复创建);
  2. 正确复制节点间的连接关系(邻居列表需指向克隆后的节点,而非原图节点)。

算法的核心思路是深度优先搜索(DFS)+ 哈希表映射:

  • 哈希表(map):存储 “原图节点值 → 克隆节点” 的映射,用于快速判断节点是否已被克隆,同时作为克隆节点的 “缓存”。
  • DFS 遍历:从起始节点出发,递归遍历所有可达节点。对于每个节点:
    • 若已克隆(存在于哈希表中),直接返回克隆节点;
    • 若未克隆,先创建克隆节点并存入哈希表,再递归克隆其所有邻居,构建克隆节点的邻居列表。

步骤 1:初始化哈希表

创建一个 map[int]*Node 类型的哈希表 m,键为原节点的 Val,值为对应的克隆节点。利用节点值唯一的特性,通过 Val 快速定位已克隆的节点。

步骤 2:DFS 递归克隆节点

  • 终止条件:若当前节点为 nil,直接返回 nil;若当前节点已被克隆(存在于哈希表中),返回哈希表中对应的克隆节点(避免重复克隆)。
  • 克隆当前节点:若节点未被克隆,创建新节点(复制 Val),并将其存入哈希表。
  • 递归克隆邻居:遍历原节点的所有邻居,递归调用 DFS 克隆每个邻居,将克隆结果加入新节点的 Neighbors 列表,建立邻居关系。

步骤 3:返回克隆结果

从初始节点开始 DFS,最终返回克隆图的对应节点。

func cloneGraph(node *Node) *Node {
	var m = make(map[int]*Node)
	var dfs func(node *Node) *Node
	dfs = func(node *Node) *Node {
		if node == nil {
			return nil
		}
		if n, ok := m[node.Val]; ok {
			return n
		}
		n := &Node{Val: node.Val}
		m[node.Val] = n
		for index := range node.Neighbors {
			n.Neighbors = append(n.Neighbors, dfs(node.Neighbors[index]))
		}
		return n
	}
	return dfs(node)
}

复杂度:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

执行结果:

  • 执行耗时:0 ms,击败了100.00% 的Go用户
  • 内存消耗:4.6 MB,击败了30.88% 的Go用户

通过次数 187.8K 提交次数 256.2K 通过率 73.3%

Related Posts

1026. 节点与其祖先之间的最大差值

## 题目描述:给定二叉树的根节点 root,找出存在于 不同 节点 A 和 B 之间的最大值 V,其中 V = |A.val - B.val|,且 A 是 B 的祖先。(如果 A 的任何子节点之一为 B,或者 A 的任何子节点是 B 的祖先,那么我们认为 A 是 B 的祖先)示例 1: ![](/img/leetcode/1026节点与其祖先之间的最大差值/tmp-tre

read more

1038. 从二叉搜索树到更大和树

## 题目描述:给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。提醒一下, 二叉搜索树 满足下列约束条件:- 节点的左子树仅包含键 小于 节点键的节点。 - 节点的右子树仅包含键 大于 节点键的节点。 - 左右子树也必须是二叉搜索树。*示例 1:***![](/img/leetcode/

read more

105. 从前序与中序遍历序列构造二叉树

## 题目描述:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。示例 1: ``` 输入: preorder = [3,9,20,15,7], inorder = [

read more

106. 从中序与后序遍历序列构造二叉树

## 题目描述:给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。示例 1: ``` 输入:inorder = [9,3,15,20,7], postorder

read more

109. 有序链表转换二叉搜索树

## 题目描述:给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。示例 1: ``` 输入: head = [-10,-3,0,5,9] 输出: [0,-3,9

read more

114. 二叉树展开为链表

## 题目描述:给你二叉树的根结点 root ,请你将它展开为一个单链表:- 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。示例 1: ``` 输入:root

read more