首页 > 其他分享 >138. 随机链表的复制

138. 随机链表的复制

时间:2024-07-10 09:01:24浏览次数:15  
标签:Node curr random next 链表 随机 138 节点

138. 随机链表的复制

递归和哈希表

时间&空间复杂度 O(n)
复杂链表的特点是每个节点除了有一个指向下一个节点的指针外,还有一个随机指针可能指向链表中的任意节点或null。通过递归和哈希表的方式,能够确保每个节点只被复制一次,并且正确地复制了next和random指针。

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;
    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
class Solution {
    Map<Node, Node> map = new HashMap<>();
    public Node copyRandomList(Node head) {
        if (head == null) {
            return null;
        }
        if (!map.containsKey(head)) {
            Node node = new Node(head.val);
            map.put(head, node);
            node.next = copyRandomList(head.next);
            node.random = copyRandomList(head.random);
        }
        return map.get(head);
    }
}

迭代 + 节点拆分

时间复杂度O(n), 空间复杂度O(1)
在不使用额外哈希表的情况下复制带有随机指针的链表。这种方法通过在原链表中插入拷贝节点来实现,具体步骤如下:

插入拷贝节点:

遍历原链表,对于每一个节点,创建一个新节点,其值与原节点相同,并将新节点插入到原节点之后。例如,对于链表 A→B→C,插入拷贝节点后变为 A→A'→B→B'→C→C'。
设置拷贝节点的随机指针:

再次遍历链表,对于每一个原节点 S,其拷贝节点 S' 的随机指针应当指向 S 的随机指针指向的节点 T 的拷贝节点 T'。即,如果 S.random 指向 T,那么 S'.random 应当指向 T'。
需要注意原节点的随机指针可能为空,此时拷贝节点的随机指针也应为空。
拆分链表:

最后,遍历链表,将原节点和拷贝节点分开,形成两个独立的链表。原链表恢复原状,新链表即为拷贝链表。
需要注意最后一个拷贝节点的后继节点为空。

假设有一个链表:A → B → C,其中每个节点除了有next指针外,还可能有指向链表中任意节点或nullrandom指针。下面是使用不需要额外哈希表的方法复制这个链表的可视化过程:

初始链表

A → B → C

步骤1:插入拷贝节点

在每个原节点后面插入一个拷贝节点,此时不处理random指针。

A → A' → B → B' → C → C'

步骤2:设置拷贝节点的随机指针

对于每个原节点,比如A,如果A.random指向C,则设置A'.random指向C'。这一步骤完成后,所有拷贝节点的random指针都会正确指向对应的拷贝节点。

A → A' → B → B' → C → C'
|    |    |    |    |    |
v    v    v    v    v    v
C    C'   A    A'   B    B'

步骤3:拆分链表

将原节点和拷贝节点分开,形成两个独立的链表。原链表恢复为A → B → C,新链表为A' → B' → C'

原链表:

A → B → C

拷贝链表:

A' → B' → C'

在这个过程中,原链表完全恢复,而新链表是原链表的深拷贝,包括正确复制的random指针。这种方法避免了使用额外的哈希表来存储节点之间的映射关系,通过巧妙地在原链表中插入拷贝节点并最后将它们分离出来,实现了空间复杂度为O(1)的深拷贝。

class Solution {
    public Node copyRandomList(Node head) {
        if (head == null) {
            return null;
        }

        // Step 1: Insert copy nodes
        Node curr = head;
        while (curr != null) {
            Node copy = new Node(curr.val);
            copy.next = curr.next;
            curr.next = copy;
            curr = copy.next;
        }

        // Step 2: Set random pointers for copy nodes
        curr = head;
        while (curr != null) {
            if (curr.random != null) {
                curr.next.random = curr.random.next;
            }
            curr = curr.next.next;
        }

        // Step 3: Separate the original and copy lists
        Node dummy = new Node(0);
        Node copyPrev = dummy;
        curr = head;
        while (curr != null) {
            copyPrev.next = curr.next;
            copyPrev = copyPrev.next;
            curr.next = curr.next.next;
            curr = curr.next;
        }

        return dummy.next;
    }
}

标签:Node,curr,random,next,链表,随机,138,节点
From: https://www.cnblogs.com/qianingmeng/p/18293104

相关文章

  • 新时代【机器学习】与【Pycharm】:【随机数据生成】与智能【股票市场分析】
    目录第一步:准备工作1.1安装必要的库小李的理解:1.2导入库小李的理解:第二步:生成和准备数据2.1生成随机股票数据小李的理解:2.2数据探索与可视化小李的理解:2.3数据处理小李的理解:2.4选择特征和标签小李的理解:第三步:拆分数据集小李的理解:第四步:训练决策树模......
  • 线性表——静态链表(插入阉割版)
    #include<bits/stdc++.h>usingnamespacestd;#defineMaxSize3typedefstructSNode{ intdata; intnext;}SLinkList[MaxSize];//初始化voidInitList(SLinkListL){ L[0].data=0; //我这里放的是链表长度 for(inti=0;i<MaxSize;i++){ L[i].next=-1; }}//......
  • 203. 移除链表元素
    给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val==val 的节点,并返回 新的头节点 。示例1:输入:head=[1,2,6,3,4,5,6],val=6输出:[1,2,3,4,5]示例2:输入:head=[],val=1输出:[]示例3:输入:head=[7,7,7,7],val=7输......
  • 单链表详解(1)
    一、顺序表的弊端1.往顺序表中间插入元素时时间要移动顺序表的一部分,当顺序表足够大时,这时时间复杂度会时O(n),运行效率会降低;2.顺序表在空间不够时增容用到realloc函数,这个函数需要拷贝原数据,申请新空间,释放旧空间,这也降低了运行效率;3.顺序表增容后可能存在空间浪费的问题......
  • 线性表——单链表
    #include<bits/stdc++.h>usingnamespacestd;typedefstructLNode{ intdata; structLNode*next;}LNode,*List;//初始化voidInitList(List&L){ L=(LNode*)malloc(sizeof(LNode)); L->next=NULL;}//头插voidListInsertHead(List&L,inte)......
  • 反转链表
    目录L206反转链表题目描述题解方法一:迭代方法二:递归L92反转链表II题目描述题解方法一:一遍扫描方法二:穿针引线L25K个一组反转链表题目描述题解方法一:模拟L206反转链表题目描述给你单链表的头节点head,请你反转链表,并返回反转后的链表。示例1:示例2:题解方法一:迭代假......
  • R语言用逻辑回归、决策树和随机森林对信贷数据集进行分类预测|附代码数据
    原文链接:http://tecdat.cn/?p=17950 最近我们被客户要求撰写关于的研究报告,包括一些图形和统计输出。 在本文中,我们使用了逻辑回归、决策树和随机森林模型来对信用数据集进行分类预测并比较了它们的性能 数据集是  credit=read.csv("gecredit.csv", header = ......
  • 【数据结构】—— 单链表(single linked list)
    文章目录1、单链表的定义优点和缺点单链表的构成2、单链表的创建初始化:3、单链表的接口实现打印尾插头插尾删头删查找在指定位置之前插入在指定位置之后插入删除指定位置的节点删除指定位置之后的节点销毁链表4、源代码1、单链表的定义单链表(SinglyLinkedList......
  • 代码随想录算法训联营第四天|LeetCode24. 两两交换链表中的节点 LeetCode19.删除链表
    系列文章目录代码随想录算法训练营第四天:代码随想录|LeetCode24.两两交换链表中的节点LeetCode19.删除链表的倒数第N个节点面试题02.07.链表相交LeetC142.环形链表文章目录系列文章目录前言一、LeetCode24.两两交换链表中的节点1、题目链接2、题解二、LeetCod......
  • 单链表在Python中的实现技巧详解
    概要链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据域和一个指向下一个节点的指针。链表的优点是插入和删除操作非常高效,特别是在需要频繁修改数据结构的情况下。本文将详细介绍如何在Python中创建单链表,并包含相应的示例代码,帮助全面掌握这一基础而重要......