立志用最少代码做最高效的表达


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

示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]

示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]

示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]

示例 4:
输入:head = []
输出:[]
解释:给定的链表为空(空指针),因此返回 null。

提示:
-10000 <= Node.val <= 10000
Node.random 为空(null)或指向链表中的节点。
节点数目不超过 1000 。


思路一:HashMap

思路:以map将新节点和旧节点映射起来,进而建立链表。
步骤
1、完成以next指针为串联的链表的建立,并建立HashMap映射
2、完成random的链表建设
缺点:冗余

class Solution {public Node copyRandomList(Node head) {/**1、根据next完成链表的复制,同时建立hash表映射2、根据hash表的映射进行random的指向*/if(head == null) return null;           //头结点为空的情况Map<Node, Node> map = new HashMap<>();   // 建立Map映射,映射原节点和被复制的节点Node copyListHead = new Node(head.val); // 复制链表的头结点map.put(head, copyListHead);            // 建立头结点间的映射Node oldTmpList1 = head.next;               // 原链表的临时遍历节点Node copyTmpList1 = copyListHead;           // 复制链表的临时遍历节点1// 1、完成next的复制while(oldTmpList1 != null) {Node newTmpList1 = new Node(oldTmpList1.val);    // 赋值链表的临时遍历节点2(因为建表需要两个节点)map.put(oldTmpList1, newTmpList1);    // 建立映射copyTmpList1.next = newTmpList1;              // 建表过程copyTmpList1 = newTmpList1;oldTmpList1 = oldTmpList1.next;}// 2、完成random的复制Node oldTmpList2 = head;Node newTmpList2 = copyListHead;           // 复制链表的临时遍历节点1while(oldTmpList2 != null) {if(oldTmpList2.random != null) {newTmpList2.random = map.get(oldTmpList2.random);}oldTmpList2 = oldTmpList2.next;newTmpList2 = newTmpList2.next;}return copyListHead;}
}

思路2:对思路1的优化

拆分成两步:
1、将新旧节点映射起来
2、进行next和random的链表建立
时间复杂度:O(n) 、 空间复杂度:O(n)

class Solution {public Node copyRandomList(Node head) {if(head == null) return null;           //头结点为空的情况Map<Node, Node>map = new HashMap<>();   // 建立Map映射,映射原节点和被复制的节点Node copyListHead = new Node(head.val); // 复制链表的头结点// 1、进行Map映射for(Node tmp = head; tmp != null; tmp = tmp.next) {if(tmp == head) map.put(head, copyListHead);    // 头结点单独判断else map.put(tmp, new Node(tmp.val));           // 建立映射}// 2、完成next的复制和random的复制for(Node tmp = head; tmp != null; tmp = tmp.next) {map.get(tmp).next = map.get(tmp.next);map.get(tmp).random = map.get(tmp.random);}return copyListHead;}
}

代码3:原地复制

思路:在原链表的每个节点后都构建一个新节点,将原来形如A->B->C的链表改为A->A'->B->B'->C->C',然后拆分两链表即可。

步骤
1、复制各个节点,构建拼接链表
2、构建各个新节点的random指针
3、拆分成两个链表

注意:本题的题意是深拷贝,即不能更改原链表。

class Solution {public Node copyRandomList(Node head) {if(head == null) return null;Node cur = head;// 1. 复制各节点,并构建拼接链表while(cur != null) {Node tmp = new Node(cur.val);tmp.next = cur.next;cur.next = tmp;cur = tmp.next;}// 2. 构建各新节点的 random 指向cur = head;while(cur != null) {if(cur.random != null)cur.next.random = cur.random.next;cur = cur.next.next;}// 3. 拆分两链表cur = head.next;Node pre = head, res = head.next;while(cur.next != null) {pre.next = pre.next.next;cur.next = cur.next.next;pre = pre.next;cur = cur.next;}pre.next = null; // 单独处理原链表尾节点return res;      // 返回新链表头节点}
}

【三次优化】剑指 Offer 35. 复杂链表的复制相关推荐

  1. 剑指 Offer 35. 复杂链表的复制

    剑指 Offer 35. 复杂链表的复制 题目 题目链接 解题思路 题目理解 解题思路 具体代码 题目 题目链接 https://leetcode-cn.com/problems/fu-za-lian ...

  2. 【LeetCode】剑指 Offer 35. 复杂链表的复制

    [LeetCode]剑指 Offer 35. 复杂链表的复制 文章目录 [LeetCode]剑指 Offer 35. 复杂链表的复制 package offer;import java.util.Ar ...

  3. 剑指offer——35复杂链表的复制

    这题很是巧妙. 突破了常规思维. 竟然可以把传入进来的链表和复制的链表链在一起.然后再算出slibling指针.最后在分离. 直接把空间复杂度变为O(1)了. 很巧妙,很实用. 题目: 请实现函数Co ...

  4. 剑指 Offer 35. 复杂链表的复制(哈希/衍生拆分图解)

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

  5. LeetCode笔记】剑指 Offer 35. 复杂链表的复制(Java、哈希表、原地算法)

    文章目录 题目描述 思路 && 代码 1. 哈希表法 2. 原地算法 二刷 题目描述 主要有两个考虑点: 不能改变原链表 新链表赋予 next.random 时,复制结点不一定存在 思 ...

  6. 【算法】剑指 Offer 35. 复杂链表的复制 【重刷】

    1.概述 地址:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/ 请实现 copyRandomList 函数,复制一个复 ...

  7. leetcode 剑指 Offer 35. 复杂链表的复制

    题意 将一个链表复制一遍后输出,这个链表除了next指针外,还有一个random指针,随机指向链表中的节点(包括自身或者NULL). 解法 生成一个新的链表,然后根据新老链表同时循环遍历,找到当前老链 ...

  8. 【LeetCode 剑指 Offer 35. 复杂链表的复制(中等)】

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

  9. 《剑指offer》-- 复杂链表的复制、字符串的排列、数组中出现次数超过一半的数字、连续子数组的最大和

    一.复杂链表的复制: 参考牛客网的chancy:https://www.nowcoder.com/questionTerminal/f836b2c43afc4b35ad6adc41ec941dba 1 ...

最新文章

  1. Spring MVC前后端的数据传输
  2. 区域链实践第一步——区域链测试环境搭建
  3. 解决Debian安装后中文乱码
  4. CentOS 7 安装nexus
  5. mysql事物及事物等级_MySQL事物原理及事务隔离级别
  6. DataGrid实现简单的行分组
  7. python正则替换查询_使用Python中的正则表达式进行搜索和替换
  8. python re模块安装_python re模块
  9. python 重定向到其他cmd_python 如何重定向到另一个终端?
  10. angularjs 服务详解
  11. 三目运算符?:结合性
  12. 二维码内容过多,生成的二维码太复杂,导致扫码的时候,过慢或者扫不出来解决方案。附二维码生成、解析工具类
  13. MFC:Ribbon界面设计
  14. 数电基础知识——原码、反码、补码
  15. 一线二线城市工作的区别
  16. 仿真动画是怎么制作的? 仿真动画类型有哪些?
  17. excel合并两列内容_技巧不求人169期 Excel打印最常用的8大技巧 Excel合并多表数据...
  18. 《花花公子》刊登1985年乔布斯专访
  19. php后端开发需要懂什么意思,PHP中的=什么意思?_后端开发
  20. CVPR 2021 | “以音动人”:姿态可控的语音驱动说话人脸

热门文章

  1. 第07讲:入门首选,Requests 库的基本使用
  2. 后端不哭!最新优化性能经验分享来啦
  3. 175 道面试必考 Go 语言题目详细解答
  4. 力扣- -阶乘函数后K个零
  5. 与WebXR共同创建者Diego Marcos一起探讨沉浸式Web的未来(上)
  6. Ukiyo-e faces dataset 浮世绘面孔数据集
  7. 两雄争霸:解读MSU2019年度视频编码大赛
  8. Puffer:专注拥塞控制、带宽预测和ABR
  9. 数据结构与算法之RandomPool结构和岛问题
  10. 开源系统管理资源大合辑