《链》接未来:力扣“复制带随机指针的链表”题解

news2024/10/7 14:34:04

在这里插入图片描述
本篇博客会讲解力扣“138. 复制带随机指针的链表”的解题思路,这是题目链接。

先来审题:
在这里插入图片描述
以下是输出示例:
在这里插入图片描述
以下是提示:
在这里插入图片描述
本题要实现复杂链表的深拷贝。复杂链表,是正常的单链表,每个结点中多存了一个指针,这个指针指向了链表的随机结点(也可能是NULL)。

本题的实现分为3个步骤:

  1. 在每个结点后面链接一个拷贝结点。
  2. 设置拷贝结点的random指针。
  3. 把拷贝结点解下来,恢复原链表。

1.链接拷贝结点

我们使用cur结点来遍历链表。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    while (cur)
    {
        
    }
}

拷贝出一个结点。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    while (cur)
    {
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
    }
}

把这个结点插入到cur和cur->next中间。为了防止代码顺序书写事物,建议先用next指针保存cur->next。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
    }
}

最后cur结点再往后走。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }
}

2.设置random指针

再次遍历链表。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        
    }
}

找到cur对应的copy和next。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
    }
}

设置copy结点的random指针。分类讨论:

  1. 如果cur的random指针为NULL,则copy的random指针也为NULL。
  2. 如果cur的random指针不为NULL,则copy的random指针在cur的random指针的下一个结点。
struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
    }
}

最后cur往后走。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }
}

3.解下拷贝结点,恢复原链表

再开始新的一轮的遍历。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }

    // 解下copy结点,恢复原链表
    cur = head;
    while (cur)
    {
        
    }
}

还是先找到对应的copy和next。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }

    // 解下copy结点,恢复原链表
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
    }
}

我们要把copy结点解下来,可以考虑尾插到新的链表中。先定义哨兵位的头结点。同时,为了省去单链表找尾结点的过程,最好记录尾指针。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }

    // 解下copy结点,恢复原链表
    // 定义哨兵位
    struct Node* newHead = (struct Node*)malloc(sizeof(struct Node));
    newHead->val = 0;
    newHead->next = NULL;
    // 记录尾结点
    struct Node* tail = newHead;
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
    }
}

把copy结点尾插到新链表中,同时更新尾指针。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }

    // 解下copy结点,恢复原链表
    // 定义哨兵位
    struct Node* newHead = (struct Node*)malloc(sizeof(struct Node));
    newHead->val = 0;
    newHead->next = NULL;
    // 记录尾结点
    struct Node* tail = newHead;
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 尾插copy
        tail->next = copy;
        tail = copy;
    }
}

别忘了恢复原链表,让cur指向next。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }

    // 解下copy结点,恢复原链表
    // 定义哨兵位
    struct Node* newHead = (struct Node*)malloc(sizeof(struct Node));
    newHead->val = 0;
    newHead->next = NULL;
    // 记录尾结点
    struct Node* tail = newHead;
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 尾插copy
        tail->next = copy;
        tail = copy;
        // 恢复原链表
        cur->next = next;
    }
}

最后迭代走起来。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }

    // 解下copy结点,恢复原链表
    // 定义哨兵位
    struct Node* newHead = (struct Node*)malloc(sizeof(struct Node));
    newHead->val = 0;
    newHead->next = NULL;
    // 记录尾结点
    struct Node* tail = newHead;
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 尾插copy
        tail->next = copy;
        tail = copy;
        // 恢复原链表
        cur->next = next;
        // 迭代
        cur = next;
    }
}

在返回前,需要释放哨兵位,然后返回新链表即可。

struct Node* copyRandomList(struct Node* head) {
	// 在每个结点后面链接一个拷贝结点
    struct Node* cur = head;
    struct Node* copy = NULL;
    struct Node* next = NULL;
    while (cur)
    {
        next = cur->next;
        // 拷贝结点
        copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        // 在cur和next中间插入copy
        cur->next = copy;
        copy->next = next;
        // 迭代
        cur = next;
    }

    // 设置copy结点的random指针
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 设置random
        if (cur->random == NULL)
            copy->random = NULL;
        else
            copy->random = cur->random->next;
        // 迭代
        cur = next;
    }

    // 解下copy结点,恢复原链表
    // 定义哨兵位
    struct Node* newHead = (struct Node*)malloc(sizeof(struct Node));
    newHead->val = 0;
    newHead->next = NULL;
    // 记录尾结点
    struct Node* tail = newHead;
    cur = head;
    while (cur)
    {
        copy = cur->next;
        next = copy->next;
        // 尾插copy
        tail->next = copy;
        tail = copy;
        // 恢复原链表
        cur->next = next;
        // 迭代
        cur = next;
    }

    // 释放哨兵位
    struct Node* del = newHead;
    newHead = newHead->next;
    free(del);
    del = NULL;

    return newHead;
}

在这里插入图片描述
这样就通过了。

总结

  1. 总思路分为3步:链接拷贝结点,设置random,解下拷贝结点。
  2. 链接拷贝结点的核心逻辑是:单链表的插入结点操作。
  3. 设置random时的核心逻辑是:copy->random = cur->random->next。
  4. 解下拷贝结点的核心逻辑是:把copy结点尾插到新链表。

感谢大家的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/529514.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Vector VN1630/40 I/O应用】-2-信号发生器

案例背景(共5页精简):该篇博客将告诉您: 将Vector VN1630A/VN1640A CAN/LIN Interface的I/O接口充当一个简易的“信号发生器”使用:高低电平(如TTL电平)和PWM波。用作信号发生器,唤醒ECU控制器(硬件唤醒,如…

C语言参悟-循环控制

C语言参悟-循环控制 一、循环综述1. C语言的循环概念2. 循环条件3. 循环单元4. 循环中断 二、for 循环三、while 循环四、do while 循环 一、循环综述 下面只是我的对于C语言的认识拙见,可以多多提出批评建议😄 计算机的诞生很大程度上就是为了来进行重…

即拼七人拼团系统开发模式,上帮下扶机制逻辑规则解析

即拼七人拼团模式是最近非常火爆的商业模式,它主要融合了二二复制和拼团两种模式玩法,在快速裂变团队的同时,还能提高用户活跃度和粘性。这个模式中最大的亮点,就是它的上帮下扶机制,今天就在这里详细说一下。 所谓上帮…

6.文本三剑客--sed

文章目录 文本三剑客sed介绍命令介绍打印内容删除替换插入分组 文本三剑客 sed 介绍 sed编辑器 sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来 编辑数据流。 sed编辑器可以根据命令来处理数据流中的数据,这些命令要么…

Robot Techology

Two-Stage Grasping: A New Bin Picking Framework for Small Objects 摘要:本文提出了一种新的抓仓框架,两级抓取,旨在精确抓取杂乱的小物体。 在第一阶段进行了对象密度估计和粗糙抓取。在第二阶段,需要进行精细的分割、检测、…

怎么制作网站?手把手教你10个网站建设的步骤!

怎么制作网站?手把手教你10个网站建设的步骤!网站建设需要进行10个步骤,首先要确定网站建设的目标,考虑用户、品牌信息和竞争对手等,避免方向错误。其次,绘制网站建设地图和原型,确定位置大小、…

2023-详解整个数据仓库建设体系

一、数据仓库的基本概念 数据仓库与数据库的区别 数据仓库分层架构 数据仓库元数据的管理 二、数仓建模方法 范式建模法 维度建模法 实体建模法 三、维度建模 维度建模中表的类型 维度建模三种模式 维度建模过程 四、实际业务中数仓分层 数据源层ODS 数据明细层DW…

老域名扫描软件-老域名采集挖掘工具

老域名挖掘软件 老域名挖掘软件是一种可以帮助用户发现已过期或未续费的老域名的工具。以下是该软件主要特点: 大数据分析:该软件通过大数据分析技术,深度挖掘互联网上的闲置老域名,发现可用的未续费或已过期域名,从…

【面试题】面试官:说说你对 CSS 盒模型的理解

前言 CSS 盒模型是 CSS 基础的重点难点&#xff0c;因此常被面试官们拿来考察候选人对前端基础的掌握程度&#xff0c;这篇文章将对 CSS 盒模型知识点进行全面的梳理。 我们先看个例子&#xff1a;下面的 div 元素的总宽度是多少呢&#xff1f; js <!DOCTYPE html> &…

第七章结构性模式—适配器模式

文章目录 适配器模式解决的问题概念结构 类适配器模式对象适配器模式接口适配器模式应用场景JDK 源码 - Reader 与 InputStream 结构型模式描述如何将类或对象按某种布局组成更大的结构&#xff0c;有以下两种&#xff1a; 类结构型模式&#xff1a;采用继承机制来组织接口和类…

AUTOSAR-MemIf

1、MemIf的功能 从AUTOSAR的架构图中可以看出&#xff0c;MemIf(Memory Abstraction Interface)模块位于Memory Hardware Abstraction。  一方面&#xff0c;NvM使用MemIf提供的接口访问NV memory&#xff08;NV memory分为两种&#xff1a;Flash和EEPROM&#xff0c;位于MCAL…

APP图标尺寸规范一文了解清楚

在进行图标设计前&#xff0c;熟知手机 app 图标尺寸规范&#xff0c;能更好地去针对不同平台设计出更极致的图标。当前智能手机系统主要以 iOS 及 Android 为主&#xff0c;APP 图标是产品给用户的第一印象&#xff0c;图标视觉设计的美感与吸引力&#xff0c;与用户是否选择下…

分子模拟力场

分子模拟力场 AMBER力场是在生物大分子的模拟计算领域有着广泛应用的一个分子力场。开发这个力场的是Peter Kollman课题组&#xff0c;最初AMBER力场是专门为了计算蛋白质和核酸体系而开发的&#xff0c;计算其力场参数的数据均来自实验值&#xff0c;后来随着AMBER力场的广泛…

冷链保温箱在冷链中扮演了什么角色?

冷链运输是指某些食品原料、经过加工的食品或半成品、特殊的生物制品在经过收购、加工、灭活后&#xff0c;在产品加工、贮藏、运输、分销和零售、使用过程中&#xff0c;其各个环节始终处于产品所必需的特定低温环境下&#xff0c;减少损耗&#xff0c;防止污染和变质&#xf…

如何用私域流量让不知名新品牌大放异彩……

说到不知名品牌&#xff0c;那minayo这个品牌应该绝大部分人都没听说过&#xff0c;因为他从诞生到今天也就刚刚一年的时间。 minayo是一家功能性食品品牌&#xff0c;专注于美容类健康食品领域&#xff0c;主要为用户提供 AG 饮料、植物酵素、美白片、胶原蛋白果冻等产品。 …

基于区域的图像分割

文章目录 基于区域的图像分割基本原理常用的算法实现步骤示例代码结论 基于区域的图像分割 基于区域的图像分割是数字图像处理中常用的一种方法&#xff0c;它通过将图像中的像素分配到不同的区域或对象来实现图像分割的目的。相比于基于边缘或阈值的方法&#xff0c;基于区域…

汉明码奇偶校验矩阵理解

首先看 汉明码 一、矩阵解释 单bit纠正&#xff08; SEC&#xff0c;single error correction &#xff09; 以数据位为8位(m)为例&#xff0c;编码位数为r&#xff0c;2^r>mr1 r最小为4 编码后位数为4812位 编码位为p1&#xff0c;p2 &#xff0c;p3, p4 p1掌控&#xff…

数据分析真的很火吗?真的有很多企业需要这样的岗位吗?求大佬指点。

“我是去年毕业的&#xff0c;因为疫情影响&#xff0c;整个就业环境都很不好&#xff0c;很多企业都裁员了。加上疫情三年基本都是玩过去&#xff0c;也没啥一技之长&#xff0c;就业就更难了。听说现在做数据分析的人很多&#xff0c;我身边的朋友都在转行做数据分析。 其实…

【2023/05/15】Rust

Hello&#xff01;大家好&#xff0c;我是霜淮子&#xff0c;2023倒计时第10天。 Share Rest belongs to the work as the eyelids to the eyes. 译文&#xff1a; 休息与工作的关系&#xff0c;正如眼睑与眼睛的关系。 Man is a born child,his power is the power of gro…

华为od题库汇总分享

​ 前言 最近有很多群友问塔子哥华为最新OD题库在哪里可以找。我索性就写篇文章介绍一下吧~。这里塔子哥还是要说一下&#xff0c;大家想进华为od还是要重视题库。因为根据无数群友&#xff0c;网友的反映。华为od就是从题库里抽题&#xff0c;不会有新题。只是每个季度题库会…