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

题目信息

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

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

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

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

返回复制链表的头节点。

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

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0n-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.randomnull 或指向链表中的节点。

思考过程和自写代码

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

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]

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

相关推荐
凌晨1681 小时前
OpenCV(十一)人脸识别三大算法LBPH、EigenFace、FisherFace
人工智能·opencv·算法
Thomas21431 小时前
spark sort shuffer 和 hash shuffer 图解对比
算法·哈希算法
AbandonForce2 小时前
简谈线程池
开发语言·c++·算法
智购科技智能售货柜2 小时前
2026自动售货机商品掉落声学计数方案:从麦克风到频谱识别的工程实践~YH
人工智能·算法
土司大王2 小时前
LeetCode hot100——实现 Trie (前缀树)
java·算法·leetcode
水龙吟啸2 小时前
华为研发岗AI方向9.9机考题复盘&分析
人工智能·python·算法·华为
小七在进步2 小时前
类和对象(一)
java·数据结构·算法
Y_Bk2 小时前
2026 ICPC EC网络预选赛第一场
算法
CarIise2 小时前
C语言字符串基础:从char数组到双指针反转算法
算法