【每日算法】复制带随机指针的链表:「哈希表」&「原地算法」|Python 主题月

简介: 【每日算法】复制带随机指针的链表:「哈希表」&「原地算法」|Python 主题月

网络异常,图片无法展示
|


题目描述



这是 LeetCode 上的 138. 复制带随机指针的链表 ,难度为 中等


Tag : 「哈希表」、「链表」


给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。


构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。


例如,如果原链表中有 X 和 Y 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 x 和 y ,同样有 x.random --> y 。


返回复制链表的头节点。


用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:


  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。


你的代码 只 接受原链表的头节点 head 作为传入参数。

 

示例 1:


网络异常,图片无法展示
|


输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
复制代码


示例 2:


网络异常,图片无法展示
|


输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
复制代码


示例 3:


网络异常,图片无法展示
|


输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
复制代码


示例 4:


输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。
复制代码


提示:


  • 0 <= n <= 1000
  • -10000 <= Node.val <= 10000


模拟 + 哈希表



如果不考虑 random 指针的话,对一条链表进行拷贝,我们只需要使用两个指针:一个用于遍历原链表,一个用于构造新链表(始终指向新链表的尾部)即可。这一步操作可看做是「创建节点 + 构建 next 指针关系」。


现在在此基础上增加一个 random 指针,我们可以将 next 指针和 random 指针关系的构建拆开进行:


  1. 先不考虑 random 指针,和原本的链表复制一样,创建新新节点,并构造 next 指针关系,同时使用「哈希表」记录原节点和新节点的映射关系;
  2. 对原链表和新链表进行同时遍历,对于原链表的每个节点上的 random 都通过「哈希表」找到对应的新 random 节点,并在新链表上构造 random 关系。


Java 代码:


class Solution {
    public Node copyRandomList(Node head) {
        Map<Node, Node> map = new HashMap<>();
        Node dummy = new Node(-1);
        Node tail = dummy, tmp = head;
        while (tmp != null) {
            Node node = new Node(tmp.val);
            map.put(tmp, node);
            tail.next = node;
            tail = tail.next;
            tmp = tmp.next;
        }
        tail = dummy.next;
        while (head != null) {
            if (head.random != null) tail.random = map.get(head.random);
            tail = tail.next;
            head = head.next;
        }
        return dummy.next;
    }
}
复制代码


Python 3 代码:


class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        hashmap = dict()
        dummy = Node(-1)
        tail, tmp = dummy, head
        while tmp:
            node = Node(tmp.val)
            hashmap[tmp] = node
            tail.next = node
            tail = tail.next
            tmp = tmp.next
        tail = dummy.next
        while head:
            if head.random:
                tail.random = hashmap[head.random]
            tail = tail.next
            head = head.next
        return dummy.next
复制代码


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


模拟(原地算法)



显然时间复杂度上无法优化,考虑如何降低空间(不使用「哈希表」)。


我们使用「哈希表」的目的为了实现原节点和新节点的映射关系,更进一步的是为了快速找到某个节点 random 在新链表的位置。


那么我们可以利用原链表的 next 做一个临时中转,从而实现映射。


具体的,我们可以按照如下流程进行:


  1. 对原链表的每个节点节点进行复制,并追加到原节点的后面;
  2. 完成 11 操作之后,链表的奇数位置代表了原链表节点,链表的偶数位置代表了新链表节点,且每个原节点的 next 指针执行了对应的新节点。这时候,我们需要构造新链表的 random 指针关系,可以利用 link[i + 1].random = link[i].random.nextii 为奇数下标,含义为 新链表节点的 random 指针指向旧链表对应节点的 random 指针的下一个值
  3. 对链表进行拆分操作。


网络异常,图片无法展示
|


Java 代码:


class Solution {
    public Node copyRandomList(Node head) {
        if (head == null) return null;
        Node dummy = new Node(-1);
        dummy.next = head;
        while (head != null) {
            Node node = new Node(head.val);
            node.next = head.next;
            head.next = node;
            head = node.next;
        }
        head = dummy.next;
        while (head != null) {
            if (head.random != null) {
                head.next.random = head.random.next;
            }
            head = head.next.next;
        }
        head = dummy.next;
        Node ans = head.next;
        while (head != null) {
            Node tmp = head.next;
            if (head.next != null) head.next = head.next.next;
            head = tmp;
        }
        return ans;
    }
}
复制代码


Python 3 代码:


class Solution:
    def copyRandomList(self, head: 'Node') -> 'Node':
        if not head:
            return None
        dummy = Node(-1)
        dummy.next = head
        while head:
            node = Node(head.val)
            node.next = head.next
            head.next = node
            head = node.next
        head = dummy.next
        while head:
            if head.random:
                head.next.random = head.random.next
            head = head.next.next
        head = dummy.next
        ans = head.next
        while head:
            tmp = head.next
            if head.next:
                head.next = head.next.next
            head = tmp
        return ans
复制代码


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


最后



这是我们「刷穿 LeetCode」系列文章的第 No.138 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完。


在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。


为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour…


在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

相关文章
|
6月前
|
存储 监控 算法
电脑监控管理中的 C# 哈希表进程资源索引算法
哈希表凭借O(1)查询效率、动态增删性能及低内存开销,适配电脑监控系统对进程资源数据的实时索引需求。通过定制哈希函数与链地址法冲突解决,实现高效进程状态追踪与异常预警。
292 10
|
6月前
|
存储 算法 安全
控制局域网电脑上网的 PHP 哈希表 IP 黑名单过滤算法
本文设计基于哈希表的IP黑名单过滤算法,利用O(1)快速查找特性,实现局域网电脑上网的高效管控。通过PHP关联数组构建黑名单,支持实时拦截、动态增删与自动过期清理,适用于50-500台终端场景,显著降低网络延迟,提升管控灵活性与响应速度。
234 8
|
11月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
221 2
|
存储 算法 数据处理
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
|
6月前
|
存储 运维 监控
局域网网络监控软件的设备连接日志哈希表 C++ 语言算法
针对局域网监控软件日志查询效率低的问题,采用哈希表优化设备连接日志管理。通过IP哈希映射实现O(1)级增删查操作,结合链地址法解决冲突,显著提升500+设备环境下的实时处理性能,内存占用低且易于扩展,有效支撑高并发日志操作。
489 0
|
存储 算法 安全
探究‘公司禁用 U 盘’背后的哈希表算法与 Java 实现
在数字化办公时代,信息安全至关重要。许多公司采取“禁用U盘”策略,利用哈希表算法高效管理外接设备的接入权限。哈希表通过哈希函数将设备标识映射到数组索引,快速判断U盘是否授权。例如,公司预先将允许的U盘标识存入哈希表,新设备接入时迅速验证,未授权则禁止传输并报警。这有效防止恶意软件和数据泄露,保障企业信息安全。 代码示例展示了如何用Java实现简单的哈希表,模拟公司U盘管控场景。哈希表不仅用于设备管理,还在文件索引、用户权限等多方面助力信息安全防线的构建,为企业数字化进程保驾护航。
|
存储 监控 算法
员工行为监控软件中的 Go 语言哈希表算法:理论、实现与分析
当代企业管理体系中,员工行为监控软件已逐步成为维护企业信息安全、提升工作效能的关键工具。这类软件能够实时记录员工操作行为,为企业管理者提供数据驱动的决策依据。其核心支撑技术在于数据结构与算法的精妙运用。本文聚焦于 Go 语言中的哈希表算法,深入探究其在员工行为监控软件中的应用逻辑与实现机制。
272 14
|
存储 监控 算法
基于 Python 哈希表算法的局域网网络监控工具:实现高效数据管理的核心技术
在当下数字化办公的环境中,局域网网络监控工具已成为保障企业网络安全、确保其高效运行的核心手段。此类工具通过对网络数据的收集、分析与管理,赋予企业实时洞察网络活动的能力。而在其运行机制背后,数据结构与算法发挥着关键作用。本文聚焦于 PHP 语言中的哈希表算法,深入探究其在局域网网络监控工具中的应用方式及所具备的优势。
348 7
|
存储 监控 算法
基于 C++ 哈希表算法的局域网如何监控电脑技术解析
当代数字化办公与生活环境中,局域网的广泛应用极大地提升了信息交互的效率与便捷性。然而,出于网络安全管理、资源合理分配以及合规性要求等多方面的考量,对局域网内计算机进行有效监控成为一项至关重要的任务。实现局域网内计算机监控,涉及多种数据结构与算法的运用。本文聚焦于 C++ 编程语言中的哈希表算法,深入探讨其在局域网计算机监控场景中的应用,并通过详尽的代码示例进行阐释。
252 4
|
存储 监控 算法
单位电脑监控软件中 PHP 哈希表算法的深度剖析与理论探究
数字化办公的时代背景下,单位电脑监控软件已成为企业维护信息安全、提升工作效率的关键工具。此类软件可全面监测员工的电脑操作行为,收集海量数据,故而高效管理和处理这些数据显得尤为重要。数据结构与算法在此过程中发挥着核心作用。本文将聚焦于哈希表这一在单位电脑监控软件中广泛应用的数据结构,并通过 PHP 语言实现相关功能,为优化单位电脑监控软件提供技术支持。
200 3
下一篇
开通oss服务