前言

这是力扣里的一道经典链表题,据说掌握此题你对链表的理解能力就是优秀水平了


题目


/*** Definition for a Node.* struct Node {*     int val;*     struct Node *next;*     struct Node *random;* };*/
struct Node* copyRandomList(struct Node* head) {}

解题思路

思路一

要复制一个链表是简单的,但这个是带有随机指针的链表,你不能确定单节点的随机指针指向哪个,这就需要动一下脑筋了。可以发现这本身是一个单链表,即链表是单向链接的,随机指针指向的节点也都是单链表内的一个节点,所以我们可以采取一个数组来记忆每个单向节点中的random是指向第几个节点(这样同时可以避免一个问题,用val值标记的话如第二个节点和第五个节点(val 均为1),就难以分辨val=11节点的random应指向哪里,而采用顺序表进行存储random指向可以解决此问题)
如何实现?
如找到第三个节点(val=11)的random指向,就要采用嵌套循环,一个循环遍历链表random指向,一个循环存储到数组中对应位置。如图示:

但这样会有一个问题,时间复杂度为O(N^2), 要优化到O(N),就不能有两个嵌套循环。


思路2

如果我们复制一遍原单向链表,将新单链表与原单链表进行链接,是不是就可以通过仅遍历一遍将原单链表的random指针指向复制到新单链表上呢? 通过画图可以发现是可行的:

   //拷贝节点链接在源节点后面struct Node* cur = head;while(cur){struct Node* copy = (struct Node*)malloc(sizeof(struct Node));struct Node* next = cur->next;copy->val = cur->val;//进行链接cur ->next = copy;copy->next = next;cur = next;}

如何链接拷贝节点的random?
我们用cur指针对原链表进行遍历,可以发现(如val =13 的copy节点),当cur指向val= 13 节点时,cur ->random 指向节点的下一个就是val= 7 的copy节点,也就是说 copy ->random = cur->random->next;
对剩余节点同样是适用的,当cur == NULL 时遍历结束, 同时应主要判断cur ->random 是否指向NULL和cur是否重置为头结点head,以便进行新一次遍历

 // 链接拷贝节点的randomcur = head; // 对cur 重置while(cur){struct Node*copy = cur ->next;struct Node* next = copy ->next; //设置next 指针,便于观察if (cur ->random == NULL){copy->random = NULL;}else {copy->random = cur->random->next;}cur = next;}

最后一步就是将拷贝节点拆解下来,进行链接成拷贝链表,同时可以把原链表恢复链接关系(不恢复OJ也能过),如何实现?只需利用尾插法再用cur指针遍历一遍,所以我们需要设置copyHead 指针(用于返回头节点)和copyTail指针用于尾插进行遍历

 //拆解拷贝节点,链接组成拷贝链表cur = head;struct Node* copyHead = NULL, *copyTail = NULL;while(cur){struct Node* copy = cur ->next;struct Node* next = copy->next;//链接原链表cur->next = next;//尾插拷贝链表if(copyTail == NULL){copyHead = copyTail = copy;}else{copyTail-> next = copy; //此处为下一个copy节点,如val=7的节点 下一个是val=13copyTail = copyTail ->next;}cur  = next;}return copyHead;
}

本题利用了链表尾插,删除等思想,对指针掌握能力要求较高

这是题解:

struct Node* copyRandomList(struct Node* head) {//拷贝节点链接在源节点后面struct Node* cur = head;while(cur){struct Node* copy = (struct Node*)malloc(sizeof(struct Node));struct Node* next = cur->next;copy->val = cur->val;cur ->next = copy;copy->next = next;cur = next;}// 链接拷贝节点的randomcur = head;while(cur){struct Node*copy = cur ->next;struct Node* next = copy ->next;if (cur ->random == NULL){copy->random = NULL;}else {copy->random = cur->random->next;}cur = next;}//拆解拷贝节点,链接组成拷贝链表cur = head;struct Node* copyHead = NULL, *copyTail = NULL;while(cur){struct Node* copy = cur ->next;struct Node* next = copy->next;//链接原链表cur->next = next;//尾插拷贝链表if(copyTail == NULL){copyHead = copyTail = copy;}else{copyTail-> next = copy; //此处为下一个copy节点,如val=7的节点 下一个是val=13copyTail = copyTail ->next;}cur  = next;}return copyHead;
}

本节完,若要任何建议请在评论区评论,有不懂可以私聊作者

【力扣】复制带随机指针的链表题解 C语言实现相关推荐

  1. 力扣-复制带随机指针的链表

    给一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点.构造这个链表的 深拷贝. 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点 ...

  2. 【刷题日记】3.复制带随机指针的链表

    目录 一.题目介绍 ​编辑 二.题目分析 三.代码实现 题目链接:138. 复制带随机指针的链表 - 力扣(LeetCode) 一.题目介绍 我们最一开始看到题目可能会没有思路,或者压根就不知道如何下 ...

  3. 138. 复制带随机指针的链表 golang

    138. 复制带随机指针的链表 这个题结构体特殊,需要更改上一篇博客的node结构体 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的 深 ...

  4. M1: 复制带随机指针的链表

    一个链表问题:复制带随机指针的链表 题目:有一个链表L,其每个节点有2个指针,一个指针next指向链表的下个节点,另一个random随机指向链表中的任一个节点,可能是自己或者为空,写一个程序,要求复制 ...

  5. LeetCode 138 复制带随机指针的链表

    题目描述 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的 深拷贝. 我们用一个由 n 个节点组成的链表来表示输入/输出中的链表.每个节点 ...

  6. python 带随机指针的链表深度复制_LeetCode:复制带随机指针的链表

    请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null. 思路: ...

  7. 【数据结构与算法】之深入解析“复制带随机指针的链表”的求解思路与算法示例

    一.题目 ① 题目描述 给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点. 构造这个链表的深拷贝,深拷贝应该正好由 n 个全新节点 ...

  8. LeetCode 138 复制带随机指针的链表-中等

    给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点. 构造这个链表的 深拷贝. 深拷贝应该正好由 n 个 全新 节点组成,其中每个新 ...

  9. LeetCode 138. 复制带随机指针的链表(哈希 / 深拷贝)

    1. 题目 给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深拷贝. <剑指Offer>同题:面试题35. 复杂链表的复制 2 ...

最新文章

  1. [python教程入门学习]python学习笔记(CMD执行文件并传入参数)
  2. SAP修改登录桌面背景图片
  3. 【学习的心得】——“快餐”的效率与“挖掘”的重要性
  4. 测试鼠标双击_鼠标环境可靠性测试是什么
  5. 逆向调试雷电思路总结
  6. cordic ip核 vivado_vivado中Cordic IP核使用——计算正余弦(sin/cos)
  7. Open vSwitch 使用
  8. 线性拟合——从最大似然估计到平方误差到huber loss
  9. 蓝牙通信-打开和关闭蓝牙设备
  10. java web分享ppt大纲 -- servlet包
  11. C++的岗位要求是什么?
  12. 如何恢复Windows默认共享
  13. [ROS] KDL + DH 参数 + 正解
  14. Python爬取视频之爱情电影及解密TS文件和两种合并ts的方法
  15. js大屏导出图片_js将canvas保存成图片并下载
  16. es6方法 数组去重 多个数组去重 数组对象去重
  17. 用C#读取二进制文件
  18. 无人驾驶传感类型和传感信息处理方法
  19. HTTP协议2)----对于传输层的详细讲解
  20. 在虚拟机中安装kali

热门文章

  1. CPU性能由主频决定吗?
  2. zcy算法入门笔记002-位图
  3. 激光钢网正确保养方法-清洗
  4. 爬爬爬--xpath
  5. 什么是微带线和带状线
  6. 咖啡汪译文 —— 2021最新IBM消息 祝贺2020年度 Code for Global挑战赛冠军Agrolly! 结识全球五强 这些方案正在争夺20万美元的大奖,并有机会看到他们的解决方案的部署。
  7. 我用过的设计模式(2)-- 单例模式
  8. [Paper Reading] Towards Conversational Recommendation over Multi-Type Dialogs
  9. Cadence OrCAD 原理图快捷键详解
  10. 我的世界java旁观者模式_我的世界基岩版开启旁观者模式教程