剑指offer-25、复杂链表的复制

题⽬描述

输⼊⼀个复杂链表(每个节点中有节点值,以及两个指针,⼀个指向下⼀个节点,另⼀个特殊指针random 指向⼀个随机节点),请对此链表进⾏深拷⻉,并返回拷⻉后的头结点。(注意,输出结果中请不要返回参数中的节点引⽤,否则判题程序会直接返回空)

思路及解答

哈希表映射

使用哈希表存储原节点和新节点的映射关系:

  1. 第一次遍历:创建所有新节点,并建立原节点到新节点的映射
  2. 第二次遍历:根据映射关系设置新节点的next和random指针
java 复制代码
public class Solution {
    public Node copyRandomList(Node head) {
        if (head == null) {
            return null;
        }
        
        // 创建哈希表存储原节点到新节点的映射
        HashMap<Node, Node> map = new HashMap<>();
        Node current = head;
        
        // 第一次遍历:创建所有新节点并建立映射
        while (current != null) {
            map.put(current, new Node(current.val));
            current = current.next;
        }
        
        // 第二次遍历:设置新节点的next和random指针
        current = head;
        while (current != null) {
            Node newNode = map.get(current);
            newNode.next = map.get(current.next);
            newNode.random = map.get(current.random);
            current = current.next;
        }
        
        return map.get(head);
    }
}

class Node {
    int val;
    Node next;
    Node random;
    
    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
  • 时间复杂度:O(n),两次遍历链表
  • 空间复杂度:O(n),需要存储所有节点的映射关系

节点插入拆分法

通过在原链表中插入新节点来避免使用额外空间:

  1. 节点复制插入:在每个原节点后面插入一个复制的新节点
  2. 设置random指针:新节点的random指向原节点random的下一个节点
  3. 链表拆分:将混合链表拆分为原链表和新链表
java 复制代码
public class Solution {
    public Node copyRandomList(Node head) {
        if (head == null) {
            return null;
        }
        
        // 第一步:在每个节点后面插入复制的节点
        Node current = head;
        while (current != null) {
            Node newNode = new Node(current.val);
            newNode.next = current.next;
            current.next = newNode;
            current = newNode.next;
        }
        
        // 第二步:设置复制节点的random指针
        current = head;
        while (current != null) {
            if (current.random != null) {
                current.next.random = current.random.next;
            }
            current = current.next.next;
        }
        
        // 第三步:拆分链表
        Node newHead = head.next;
        current = head;
        while (current != null) {
            Node temp = current.next;
            current.next = temp.next;
            if (temp.next != null) {
                temp.next = temp.next.next;
            }
            current = current.next;
        }
        
        return newHead;
    }
}
  • 时间复杂度:O(n),三次遍历链表
  • 空间复杂度:O(1),只使用固定数量的指针变量
相关推荐
阿俊-全栈开发4 小时前
LikeShop 单商户SaaS商城分销模块二开:佣金计算与结算逻辑实现
java·开发语言·微服务·likeshop·likeshop开源商城·likeshop多商户
wuminyu7 小时前
C++协程实现接收端的零拷贝Buffer管理原理剖析
java·linux·c语言·jvm·c++
蜗牛互联网9 小时前
WSL Containers GA:本地AI容器的生命周期、网络与治理验收
java·网络·人工智能·后端
龙亘川10 小时前
铭记英烈守初心,数字强基促服务:亘川智城退役军人服务系统的实践与价值
java·数据库·人工智能
OxYGC10 小时前
[AI工程] Spring AI 第廿一篇:存量 REST 接口的 MCP 化改造实录——工具从哪条路径注册、参数描述怎么写、身份怎么过去
java·人工智能·spring
Zhou14113610 小时前
SpringBoot_02_自动配置原理
java·spring boot·后端
FYKJ_201011 小时前
SSM校园失物招领系统41452-计算机课程设计、毕业设计
java·vue.js·spring boot·python·mysql·typescript·spark
kv11011 小时前
Android studio国内开发有关
java·数据库·android studio
卓怡学长11 小时前
w198基于springboot始于足下健康打卡平台的设计与实现
java·spring boot·spring·intellij-idea
阿狗童鞋11 小时前
Java并发编程实战指南
java·开发语言