LeetCode hot 100 — 138. 随机链表的复制

题目信息

LeetCode hot 100 --- 138. 随机链表的复制

给你一个长度为 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]]

提示:

  • 0 <= n <= 1000
  • -104 <= Node.val <= 104
  • Node.random 为 null 或指向链表中的节点。

思考过程和自写代码

简单来说就是一个深拷贝构造的情景。

node加入一个random指针随机指向null节点或者是链表中的任意一个节点。

我的思考逻辑是要走两遍原链表的循环,先按照next顺序构造出链表,然后通过random的映射进行random指针的完善。

第一版本代码

python 复制代码
"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution:
    def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        # 进行两轮?先进行next的,也就是完全链表的构造(避免random指向的节点尚未创建)
        if head is None: return None
        random_map = {} # 每个位置的random指向的地址 index.random = 具体的地址
        orin_map = {} # 地址->index 每个地址对应的Index
        now_map = {} # 深copy后的index到地址
        random_map[1] = head.random
        orin_map[head] = 1
        '''
        第一遍遍历的时候, 记录下random_map and orin_map; 
        然后第二遍遍历deep copy的链表的时候:
            - random_map[i] = 原链表random指向的地址
            - orin_map[random_map[i]] -----> 拿到对应的index序号
            - curr.next = now_map[index] = now_map[orin_map[random_map[i]]]
        '''
        res = Node(head.val, None, None)
        r = res
        now_map[1] = res

        pre, curr = head, head.next
        cnt = 1
        while curr is not None: 
            tmp = Node(curr.val, None, None)
            r.next = tmp
            cnt += 1
            random_map[cnt] = curr.random
            orin_map[curr] = cnt
            now_map[cnt] = tmp

            pre = curr
            curr = curr.next
            r = r.next
        # 完成链表的创建, 开始random的创建
        # 重新初始化变量的位置
        pre, curr = head, head.next
        r = res
        for i in range(1, cnt + 1):
            address = random_map[i]  # 拿到对应的地址
            index = orin_map[address]
            deep_copy_address = now_map[index]
            r.random = deep_copy_address
            r = r.next
        return res

改版本代码编译不通过,仅代表初步的思路和大体的框架

逻辑 / 代码优化

大体的方向 / 逻辑是正确的,有几个关键的问题 / 需要优化的点

**最大的问题是:没有考虑到random为None的情况。**如果为none,index = orin_mapaddress 语句会产生报错。

需要优化的几个点:

  • 数据映射过于弯绕。数据映射现有的逻辑是 源节点random地址------>源节点序号------>新节点地址,逻辑上没有问题,但没有必要通过中间的序号做桥接。可以直接进行源节点对象------>新节点对象的映射,更为直接。
  • 部分变量没有使用。比如在第二轮的遍历过程当中,pre and curr都没有被使用到

简化后的代码简洁非常多。

创建新节点;建立旧新节点的映射关系;建立指针关系

第二版代码-终版

python 复制代码
"""
# Definition for a Node.
class Node:
    def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution:
    def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
        if head is None: return None
       
        copy_map = {None: None}     #建立新旧节点之间的映射关系
        curr = head
        while curr is not None:
            copy_map[curr] = Node(curr.val)  # 旧节点映射新节点
            curr = curr.next
        curr = head
        # 开始建立next and random关系
        while curr is not None:
            new_node = copy_map[curr]
            new_node.next = copy_map[curr.next]
            new_node.random = copy_map[curr.random]
            curr = curr.next
        return copy_map[head]

简洁很多了,逻辑也非常的清楚

相关推荐
不会就选b1 天前
算法日常・每日刷题--<贪心>25
数据结构·算法
Cccp.1231 天前
【leetcode】(七)前缀树和贪心算法
数据结构·leetcode·贪心算法
千里码aicood1 天前
基于CART算法的图书分类系统设计与实现
数据库·算法·分类
做cv的小昊1 天前
【World Model】π0.5:a Vision-Language-Action Model with Open-World Generalization
人工智能·算法·机器学习·大模型·多模态·vla·世界模型
لا معنى له1 天前
World-In-World: World Models in a Closed-Loop World
算法
Discipline10291 天前
尼泊尔河流流量:天气驱动的预测与高流量风险
人工智能·算法
XuCoder1 天前
改一个数,右边全得重算,这题怎么扛住两万次查询
算法
小羊没烦恼!1 天前
在Scrum中实施敏捷建模
java·开发语言·windows·算法·c#
weixin_307779131 天前
基于睿擎工业开发平台的预训练视觉模型轻量化适配与低代码部署优化
开发语言·算法