0

0

LeetCode 133. 克隆图:DFS 深拷贝的正确实现方法

心靈之曲

心靈之曲

发布时间:2025-12-29 19:54:22

|

338人浏览过

|

来源于php中文网

原创

LeetCode 133. 克隆图:DFS 深拷贝的正确实现方法

本文详解如何用 dfs 正确实现无向连通图的深拷贝,重点解决因忽略图中环而导致的重复节点创建问题,并提供简洁、健壮、可复用的递归解决方案。

在 LeetCode 133. Clone Graph 中,目标是为给定的连通无向图生成一个完全独立的深拷贝——即新图中每个节点及其邻接关系都需全新构造,且任意两个节点间的关系(尤其是环结构)必须与原图严格一致。常见错误(如题中原始代码)在于仅用 set 记录已访问的 val 值,却未保存对应克隆节点的引用,导致遇到已访问节点时仍新建节点,破坏图结构一致性。

核心问题在于:图可能含环,而深拷贝必须复用已创建的克隆节点,而非重复实例化。
因此,状态映射容器不能只是 visited: Set[int],而应升级为 visited: Dict[int, Node],以支持“查表复用”——当 DFS 再次抵达某 val 对应的节点时,直接返回其已有克隆体。

以下是推荐的 DFS 实现(清晰版):

"""
# 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: Dict[int, 'Node'] = {}

        def dfs(n: Optional['Node']) -> Optional['Node']:
            if not n:
                return None
            if n.val in visited:
                return visited[n.val]  # 复用已克隆节点,避免环导致重复创建

            clone = Node(n.val)  # 创建新节点
            visited[n.val] = clone  # 立即注册,防止后续递归重复创建

            # 递归克隆所有邻居,并追加到当前克隆节点的 neighbors 列表
            for neighbor in n.neighbors:
                clone.neighbors.append(dfs(neighbor))

            return clone

        return dfs(node)

关键设计亮点:

Figma
Figma

Figma 是一款基于云端的 UI 设计工具,可以在线进行产品原型、设计、评审、交付等工作。

下载
  • 返回式递归:dfs() 返回克隆后的节点,消除冗余参数,逻辑更内聚;
  • 即时注册:在创建 clone 后立即存入 visited,确保同一节点值在任何调用深度下均命中缓存;
  • 零特判:无需单独处理 node is None 或 len(node.neighbors) == 0,递归自然覆盖所有边界情况;
  • 强类型提示:显式标注 Dict[int, 'Node'] 和返回类型,提升可读性与 IDE 支持。

⚠️ 注意事项:

  • 节点 val 在题目中保证唯一(1-indexed 且无重复),故可用 val 作哈希键;若实际场景中 val 不唯一,则必须改用 id(node) 或自定义唯一标识;
  • 本解法时间复杂度为 O(N + E)(N 为节点数,E 为边数),空间复杂度为 O(N)(哈希表 + 递归栈);
  • 若需迭代式 DFS/BFS 实现,可配合栈/队列 + 同样 Dict[int, Node] 映射完成,原理一致。

该方案已通过 LeetCode 全部测试用例(包括含环图如 [[2,4],[1,3],[2,4],[1,3]]),是图深拷贝问题的标准范式。

相关专题

更多
string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

311

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

517

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

48

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

188

2025.08.29

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

364

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

558

2023.08.10

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

364

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

558

2023.08.10

俄罗斯搜索引擎Yandex最新官方入口网址
俄罗斯搜索引擎Yandex最新官方入口网址

Yandex官方入口网址是https://yandex.com;用户可通过网页端直连或移动端浏览器直接访问,无需登录即可使用搜索、图片、新闻、地图等全部基础功能,并支持多语种检索与静态资源精准筛选。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1

2025.12.29

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
HTML5/CSS3/JavaScript/ES6入门课程
HTML5/CSS3/JavaScript/ES6入门课程

共102课时 | 6.5万人学习

前端基础到实战(HTML5+CSS3+ES6+NPM)
前端基础到实战(HTML5+CSS3+ES6+NPM)

共162课时 | 18.4万人学习

第二十二期_前端开发
第二十二期_前端开发

共119课时 | 12.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号