LeetCode 133 题解:用 DFS 正确实现图的深拷贝(含循环处理)
技术百科
花韻仙語
发布时间:2025-12-29
浏览: 次 本文详解 leetcode 133. clone graph 的 dfs 深拷贝实现要点,重点解决因忽略图中环导致的重复节点创建问题,并提供简洁、健壮、可复用的递归解决方案。
在实现无向图的深拷贝时,一个常见误区是仅用 set 记录已访问节点值(如 visited = set()),却未保存对应克隆节点的引用。这会导致同一原始节点被多次克隆——尤其当图中存在环(cycle)或多个入边时,违反“深拷贝”要求(即结构一致 + 引用独立 + 节点唯一),最终使输出图结构错误,无法通过 LeetCode 测试用例。
核心问题在于:DFS 遍历中,若邻居节点 neighbor 已被访问过,你不应新建 Node(neighbor.val),而应复用此前已创建的克隆节点。为此,visited 必须从 set 升级为哈希映射(dict),以支持“值 → 克隆节点”的快速查找与复用。
以下是推荐的正确实现(带详细注释):
"""
# Definition for a Node.
class Node:
def __init__(self, val=0, neighbors=None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []
"""
from typing import Optional, Dict
class Solution:
def cloneGraph(self, node: Optional['Node']) -> Optional['Node']:
# visited: {original_node.val -> cloned_node}
visited: Dict[int, 'Node'] = {}
def dfs(n: Optional['Node']) -> Optional['Node']:
if not n:
return None
# 若该节点已被克隆,直接返回缓存的克隆体(关键!处理环/多入边)
if n.val i
n visited:
return visited[n.val]
# 否则创建新节点,并立即加入 visited(避免后续递归重复创建)
clone = Node(n.val)
visited[n.val] = clone
# 递归克隆所有邻居,并挂载到当前克隆节点上
for neighbor in n.neighbors:
clone.neighbors.append(dfs(neighbor))
return clone
return dfs(node)✅ 关键设计亮点:
-
状态复用而非标记跳过:visited 存储的是
映射,而非布尔标记;每次进入 dfs 先查表,命中即复用,确保每个原始节点至多生成一个克隆体。 - 无特殊边界处理:空节点、单节点、孤立节点等均由 dfs 统一处理,逻辑更简洁、鲁棒性更强。
- 返回式递归:dfs 返回克隆节点,消除副作用参数(如原代码中的 copy 参数),符合函数式风格,降低出错概率。
⚠️ 注意事项:
- 不可使用 id(node) 或 node 对象本身作为字典 key(因图中节点可能重复 val 但不同实例,且 LeetCode 测试环境对象身份不稳定);必须用 node.val 作为键(题设保证节点值唯一)。
- neighbors 列表必须逐个 dfs 递归填充,不可浅拷贝(如 copy.neighbors = n.neighbors[:]),否则仍共享原始引用。
- 本解法时间复杂度为 O(N + E),空间复杂度为 O(N)(递归栈 + visited 字典),符合最优要求。
该方案已通过 LeetCode 所有测试用例(包括含环图、大图、单节点图等),是解决图深拷贝问题的标准范式。
# 的是
# 多个
# 已被
# 不应
# 而非
# app
# 复用
# 图中
# 循环
# 递归
# 对象
# 栈
# node
# 遍历
# 布尔
# copy
# leetcode
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- php8.4如何调用com组件_php8.4win
- Drupal 中渲染节点时出现 HTML 标签嵌套
- LINUX下如何配置VLAN虚拟局域网_在LINU
- MAC怎么在照片中添加水印_MAC自带编辑工具文字
- Mac怎么设置鼠标滚动速度_Mac鼠标设置详细参数
- Windows10怎样设置家长控制_Windows
- Win11怎么更改电脑密码_Windows 11修
- 新手学PHP架构总混淆概念咋办_重点梳理【教程】
- Win11怎么看电池循环次数_Win11笔记本电池
- Win11怎么设置快速访问主页_Windows11
- 如何用正则与预处理高效拦截带干扰符的恶意域名
- 如何在JavaScript中动态拼接PHP的bas
- Win11如何添加/删除输入法 Win11切换中英
- Windows10系统怎么查看CPU核心数_Win
- 短链接怎么用php还原_从基础原理到代码实现教学【
- Win11怎么退出高对比度模式_Win11取消反色
- Windows10如何更改桌面背景_Win10个性
- Windows10电脑怎么设置防火墙出站规则_Wi
- Win11怎样激活系统密钥_Win11系统密钥激活
- Win10怎样卸载TeamViewer_Win10
- 手机php怎么转mp4_手机端php文件转mp4a
- php下载安装选zip还是msi格式_两种安装包对
- Python多线程使用规范_线程安全解析【教程】
- 如何使用Golang写入二进制文件_Golang
- 如何使用Golang实现云原生应用弹性伸缩_自动应
- Win10如何卸载微软拼音输入法 Win10只保留
- Win11怎么连接蓝牙耳机_Win11蓝牙设备配对
- Win11怎么关闭应用权限_Windows11相机
- Windows11怎么用“记事本”自动换行与编码
- c++怎么操作redis数据库_c++ hired
- php订单日志怎么导出excel_php导出订单日
- Win11色盲模式怎么开_Win11屏幕颜色滤镜设
- Windows10电脑怎么设置电源按钮_Win10
- php怎么下载安装后设置默认字符集_utf8配置步
- Win11鼠标灵敏度怎么调 Win11鼠标指针移动
- Windows如何使用BitLocker To G
- Python抽象类与接口设计_规范说明【指导】
- C++ STL算法库怎么用?C++常用算法函数(s
- mac怎么退出id_MAC退出iCloud账号与A
- Win11如何暂停系统更新 Win11暂停更新最长
- Windows10电脑怎么设置文件权限_Win10
- c++ reinterpret_cast怎么用 c
- 获取 PHP 文件最后修改时间的正确方法
- Windows怎样关闭开始菜单推荐广告_Windo
- Windows资源管理器总是卡顿或重启怎么办?(修
- 如何在Golang中实现并发消息队列消费者_Gol
- 如何使用Golang实现微服务状态监控_Golan
- Go 中 := 短变量声明的类型推导机制详解
- 如何在Golang中处理云原生事件_使用Event
- 如何使用Golang实现多重错误处理_Golang

n visited:
return visited[n.val]
# 否则创建新节点,并立即加入 visited(避免后续递归重复创建)
clone = Node(n.val)
visited[n.val] = clone
# 递归克隆所有邻居,并挂载到当前克隆节点上
for neighbor in n.neighbors:
clone.neighbors.append(dfs(neighbor))
return clone
return dfs(node)
QQ客服