LeetCode Hot100(58/100)——138. 随机链表的复制

文章目录

一、题目简介

给你一个长度为 n 的链表,每个节点包含两个指针:

  • next:指向下一个节点
  • random:指向链表中的任意节点或 null

要求你深拷贝这个链表,并返回复制后的链表头节点。

深拷贝意味着:

  • 新链表中的节点是全新创建的
  • next 和 random 的指向关系与原链表完全一致
  • 不能复用原链表的任何节点

二、节点结构说明

java 复制代码
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}

三、问题难点分析

与普通链表拷贝不同,本题的难点在于:

  1. random 指针可能:
    • 指向前面的节点
    • 指向后面的节点
    • 指向自身
    • 为 null
  2. 拷贝时,必须确保 random 指向的是"新节点"而不是旧节点
  3. random 的指向关系在拷贝过程中并不具备天然的"先后顺序"

四、解法一:哈希表映射(最直观解法)

核心思想

旧节点 → 新节点,一一映射

使用 HashMap<Node, Node> 保存原节点与复制节点的对应关系。


解题步骤

第一步:复制所有节点(只处理 val)
text 复制代码
原链表: A -> B -> C
复制后: A' -> B' -> C'

建立映射关系:

复制代码
A  -> A'
B  -> B'
C  -> C'
第二步:处理 next 和 random 指针
  • newNode.next = map.get(oldNode.next)
  • newNode.random = map.get(oldNode.random)

过程示意(时序图)

新链表节点 HashMap 原链表节点 新链表节点 HashMap 原链表节点 put(OldNode, NewNode) get(OldNode.next) get(OldNode.random) 设置 next / random


Java 实现

java 复制代码
public Node copyRandomList(Node head) {
    if (head == null) {
        return null;
    }

    Map<Node, Node> map = new HashMap<>();

    // 1. 复制节点
    Node cur = head;
    while (cur != null) {
        map.put(cur, new Node(cur.val));
        cur = cur.next;
    }

    // 2. 复制指针
    cur = head;
    while (cur != null) {
        Node newNode = map.get(cur);
        newNode.next = map.get(cur.next);
        newNode.random = map.get(cur.random);
        cur = cur.next;
    }

    return map.get(head);
}

复杂度分析

指标 复杂度
时间复杂度 O(n)
空间复杂度 O(n)(HashMap)

优缺点总结

✅ 优点

  • 思路直观
  • 容易实现
  • 不易出错

❌ 缺点

  • 需要额外 O(n) 空间

五、解法二:原地复制(O(1) 额外空间,面试高频)

核心思想

把复制节点直接插入到原节点后面

利用链表结构本身,避免使用额外的哈希表。


整体流程概览

原链表
复制节点并插入原节点后
设置复制节点的 random 指针
拆分成原链表和新链表


步骤一:复制节点并插入

text 复制代码
原链表:
A -> B -> C

插入后:
A -> A' -> B -> B' -> C -> C'

示例图

A
A1
B
B1
C
C1


Java 实现(步骤一)

java 复制代码
Node cur = head;
while (cur != null) {
    Node copy = new Node(cur.val);
    copy.next = cur.next;
    cur.next = copy;
    cur = copy.next;
}

步骤二:设置 random 指针

关键观察

如果:

复制代码
cur.random = X

那么:

复制代码
cur.next.random = X.next

因为 X.next 正好是 X 的复制节点。


Java 实现(步骤二)

java 复制代码
cur = head;
while (cur != null) {
    if (cur.random != null) {
        cur.next.random = cur.random.next;
    }
    cur = cur.next.next;
}

步骤三:拆分链表

将交织在一起的链表拆分成:

  • 原链表
  • 新链表

Java 实现(步骤三)

java 复制代码
Node dummy = new Node(0);
Node copyCur = dummy;
cur = head;

while (cur != null) {
    copyCur.next = cur.next;
    cur.next = cur.next.next;

    copyCur = copyCur.next;
    cur = cur.next;
}

return dummy.next;

六、完整 Java 代码(O(1) 空间解法)

java 复制代码
public Node copyRandomList(Node head) {
    if (head == null) {
        return null;
    }

    Node cur = head;

    // 1. 复制节点并插入
    while (cur != null) {
        Node copy = new Node(cur.val);
        copy.next = cur.next;
        cur.next = copy;
        cur = copy.next;
    }

    // 2. 设置 random
    cur = head;
    while (cur != null) {
        if (cur.random != null) {
            cur.next.random = cur.random.next;
        }
        cur = cur.next.next;
    }

    // 3. 拆分链表
    Node dummy = new Node(0);
    Node copyCur = dummy;
    cur = head;

    while (cur != null) {
        copyCur.next = cur.next;
        cur.next = cur.next.next;

        copyCur = copyCur.next;
        cur = cur.next;
    }

    return dummy.next;
}

七、复杂度分析(原地解法)

指标 复杂度
时间复杂度 O(n)
空间复杂度 O(1)

八、两种解法对比总结

方案 时间复杂度 空间复杂度 难度 适用场景
HashMap O(n) O(n) ⭐⭐ 快速实现
原地复制 O(n) O(1) ⭐⭐⭐⭐ 面试高频
相关推荐
Cccp.12312 小时前
【leetcode】(七)前缀树和贪心算法
数据结构·leetcode·贪心算法
优质酸酸乳17 小时前
力扣100题之21合并两个有序链表
算法·leetcode·链表
旖旎夜光17 小时前
LeetCode 137 : 只出现一次的数字 II(位运算) —— 题解
c++·笔记·学习·算法·leetcode·力控
yi01118 小时前
LeetCode 134 加油站:从 双循环暴力 演变到 贪心
linux·算法·leetcode
yi01119 小时前
DAY 14: LeetCode 394. 字符串解码|递归和栈到底怎么处理嵌套?
数据结构·笔记·python·算法·leetcode
P.D.Wei20 小时前
[Leetcode 1614] 括号的最大嵌套深度
算法·leetcode·职场和发展
blxr_20 小时前
力扣hot100寻找重复数https://leetcode.cn/problems/find-the-duplicate-number/
算法·leetcode·职场和发展
_不会dp不改名_21 小时前
leetcode_1614嵌套括号的最大深度
算法·leetcode·职场和发展
sogw-三叶草️1 天前
LeetCode206. 反转链表
数据结构·链表
alphaTao1 天前
LeetCode 每日一题 2026/9/21-2026/9/27
python·算法·leetcode