链接

https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/
难度: #中等

题目

请实现 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 。

代码框架

/*
// 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 {public Node copyRandomList(Node head) {}
}

题目解析

解答思路1:
使用递归方式遍历链表,
从后往前复制链表,
在递归遍历下一个结点之前,
首先复制当前结点到新结点,
然后把旧结点映射的新结点,
然后遍历下一个结点,
直到最后一个结点,
这时Map中有全部旧结点到新结点的映射关系,
然后从最后一个结点开始处理random值,
首先找到random指向的旧结点,
根据旧结点找到新的结点即可。

解答思路2:
使用2个for循环,
第1个for循环复制链表的所有节点,
同时保存旧结点对应的新结点,
第2个for循环处理next和random值,
根据next和random指向的旧结点,
分别找到其对应的新的结点即可。
该思路的优点是容易理解,
并且代码实现很简单。

解答思路3:
原地修改的方法:
复制一个新的节点在原有节点之后,
如1 -> 2 -> 3 -> null 复制完
是1 -> 1 -> 2 -> 2 -> 3 - > 3 -> null,
从头开始遍历链表,
通过 cur.next.random = cur.random.next 可以将复制节点的Random串起来,
注意判断 cur.random 是否存在
最后将复制完的链表一分为二。
该思路相比思路1并未有本质上的优化提升,
同时又很大的操作链表的复杂度,
但是可以扩展链表的使用思路,
且锻炼对链表的操作能力。

测试用例

package edu.yuwen.sowrd.num35.solution;import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;import edu.yuwen.sowrd.num35.Node;
import edu.yuwen.sowrd.num35.sol3.Solution;public class SolutionTest {/*** 示例1:* 输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]*  输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]*/@Testpublic void testCase1() {Solution solution = new Solution();Node head = getNodeHead();Node newHead = solution.copyRandomList(head);// 返回的新链表不能和旧链表相同Assertions.assertNotEquals(head, newHead);for (Node old = head, newN = newHead; old != null; old = old.next, newN = newN.next) {// 检查是否是深拷贝Assertions.assertNotEquals(old, newN);Assertions.assertEquals(old.val, newN.val);}for (Node node = head; node != null; node = node.next) {System.out.println(node.val + " ,next->" + getNextValue(node)+ " ,random->" + getRandomValue(node));}System.out.println("-----------------------------------");for (Node node = newHead; node != null; node = node.next) {System.out.println(node.val + " ,next->" + getNextValue(node)+ " ,random->" + getRandomValue(node));}}public Node getNodeHead() {Node node0 = new Node(7);Node node1 = new Node(13);Node node2 = new Node(11);Node node3 = new Node(10);Node node4 = new Node(1);node0.next = node1;node1.next = node2;node2.next = node3;node3.next = node4;node4.next = null;node0.random = null;node1.random = node0;node2.random = node4;node3.random = node2;node4.random = node0;Node head = node0;return head;}public Integer getRandomValue(Node node) {return node.random == null ? null : node.random.val;}public Integer getNextValue(Node node) {return node.next == null ? null : node.next.val;}/*** 输入:head = []* 输出:[]* 解释:给定的链表为空(空指针),因此返回 null。*/@Testpublic void testCase2() {Solution solution = new Solution();Node head = null;Node newHead = solution.copyRandomList(head);// 返回的新链表不能和旧链表相同Assertions.assertEquals(null, newHead);}
}

解答1 推荐

package edu.yuwen.sowrd.num35.sol1;import java.util.HashMap;
import java.util.Map;import edu.yuwen.sowrd.num35.Node;/***解答思路1:*使用递归方式遍历链表,  *从后往前复制链表,*在递归遍历下一个结点之前,*首先复制当前结点到新结点,  *然后把旧结点映射的新结点,  *然后遍历下一个结点,  *直到最后一个结点,*这时Map中有全部旧结点到新结点的映射关系,*然后从最后一个结点开始处理random值,  *首先找到random指向的旧结点,  *根据旧结点找到新的结点即可。 */
public class Solution {// 映射旧的结点对应的新的结点Map<Node, Node> old2New = new HashMap<>();public Node copyRandomList(Node head) {// 头结点为空,或者处理到尾结点了if (head == null) {return null;}Node newNode = new Node(head.val);old2New.put(head, newNode);// 递归处理下一个结点,并且获得下一个结点Node nextNode = copyRandomList(head.next);// 当前结点指向下一个结点newNode.next = nextNode;// HashMap的get()入参为null,会返回nullNode newRandomNode = old2New.get(head.random);newNode.random = newRandomNode;return newNode;}
}

解答2

package edu.yuwen.sowrd.num35.sol2;import java.util.HashMap;
import java.util.Map;import edu.yuwen.sowrd.num35.Node;/*** 解答思路2:* 使用2个for循环,  * 第1个for循环复制链表的所有节点,  * 同时保存旧结点对应的新结点,  * 第2个for循环处理next和random值,* 根据next和random指向的旧结点,  * 分别找到其对应的新的结点即可。 */
public class Solution {// 记录旧的结点对应的新的结点Map<Node, Node> old2New = new HashMap<>();public Node copyRandomList(Node head) {// 头结点为空,或者处理到尾结点了if (head == null) {return null;}// 创建新结点,并且映射旧结点到新结点的for (Node cur = head; cur != null; cur = cur.next) {Node newNode = new Node(cur.val);old2New.put(cur, newNode);}// 根据映射表,更新新链表的每个结点Node newCur = old2New.get(head);for (Node cur = head; cur != null; cur = cur.next) {newCur.next = old2New.get(cur.next);newCur.random = old2New.get(cur.random);// 新链表移动到下一个结点newCur = newCur.next;}// 返回新链表的头结点return old2New.get(head);}
}

解答3

package edu.yuwen.sowrd.num35.sol3;import edu.yuwen.sowrd.num35.Node;/*** 解答思路3:* 原地修改的方法:* 复制一个新的节点在原有节点之后,* 如1 -> 2 -> 3 -> null 复制完* 是1 -> 1 -> 2 -> 2 -> 3 - > 3 -> null,* 从头开始遍历链表,* 通过 cur.next.random = cur.random.next 可以将复制节点的Random串起来,* 注意判断 cur.random 是否存在* 最后将复制完的链表一分为二。**/
public class Solution {public Node copyRandomList(Node head) {if (head == null) {return null;}// 由于插入了复制过的结点,要跳过下一个结点for (Node cur = head; cur != null; cur = cur.next.next) {// 在当前结点插入复制的结点Node newN = new Node(cur.val);newN.next = cur.next;cur.next = newN;}// 根据原节点的Random初始化复制节点的Randomfor (Node cur = head; cur != null; cur = cur.next.next) {Node newN = cur.next;if (cur.random != null) {// 不直接使用当前节点的random,而是指向下一个复制的结点newN.random = cur.random.next;}}// 保存复制链表的头结点Node newHead = head.next;// 将复制的链表拆分出来for (Node cur = head; cur != null; cur = cur.next) {Node newN = cur.next;// 当前结点指向原始链表的下一个结点cur.next = newN.next;if (newN.next != null) {// 复制链表的结点指向下一个结点的复制节点newN.next = newN.next.next;}}return newHead;}
}

http://www.taodudu.cc/news/show-1250937.html

相关文章:

  • 58 - II. 左旋转字符串
  • 03. 数组中重复的数字
  • 53 - II. 0~n-1中缺失的数字
  • 04. 二维数组中的查找
  • 11. 旋转数组的最小数字
  • 50. 第一个只出现一次的字符
  • 32 - I. 从上到下打印二叉树
  • 32 - II. 从上到下打印二叉树 II
  • 32 - III. 从上到下打印二叉树 III
  • 26. 树的子结构
  • PostgreSQL数据库密码
  • SpringBoot中使用Hibernate Validator校验工具类
  • 28. 对称的二叉树
  • 解决tomcat的undeploy
  • 解决eclipse出现The superclass javax.servlet.http.HttpServlet was not found on the Java Build Path
  • 下载安装neo4j
  • vue-drag-resize实线页面的拖拽与缩放
  • 解决IDEA不能编译XML文件
  • 播放视频和音频文件java
  • 实时获取屏幕大小
  • vue部分样式无法修改
  • vue中根据搜索内容跳转到页面指定位置
  • Duplicate entry ‘‘ for key ‘***‘
  • transferto遇到的问题java.io.FileNotFoundException: C:\Users\Administrator\AppData\Local\Temp
  • Spring的jar包下载
  • *** is required and cannot be removed from the server
  • Tomcat 服务器介绍和使用
  • 第一个 Web 程序
  • Servlet 介绍
  • 集成 Tomcat、 Servlet 的生命周期

35. 复杂链表的复制相关推荐

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

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

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

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

  3. 剑指offer:面试题35. 复杂链表的复制

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

  4. 【三次优化】剑指 Offer 35. 复杂链表的复制

    立志用最少代码做最高效的表达 请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意 ...

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

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

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

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

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

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

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

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

  9. 剑指offer面试题35. 复杂链表的复制(DFS)(深拷贝)

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

最新文章

  1. luogu P3393 逃离僵尸岛(点权最短路 + 多源BFS)
  2. 政府免费WiFi遭吐槽:近七成网友表示从未用过
  3. Java 面向对象:super关键字的理解
  4. 你真的会使用SQL Server的备份还原功能吗?之一:恢复模型
  5. SpringBoot 2.1.0 整合 WebSocket 通信
  6. 服务器cpu占用过高一般是什么原因,常见云服务器CPU占用100%问题原因及解决办法...
  7. 使用SPSS对数据异常值进行探索分析
  8. Python中pass是什么?
  9. iOS开发篇(二)自定义评分星级条RatingBar
  10. MFC radio button 设置默认选中
  11. 计算机在机械智能制造中的应用,机电一体化技术应用于智能制造中的优势研究...
  12. 玉米社:抖音账号被限流了怎么办?一步步教你解除限制
  13. 2018-8-28-win10-uwp-MVVM入门
  14. PMO如何有效搭建项目管理体系︱伯俊软件PMO经理李双燕
  15. 软件工程师,用100天时间让CSDN粉丝数从0狂飙到10000
  16. 初学者都会学习有关电控制图软件EPLAN的安装,下面有破解版本2.7,值得一看
  17. NGUI 中,长技能图标显示技能Tips的核心代码
  18. 日语中 “不得不”的6种表达,你都学会了吗?
  19. 谷歌浏览器iframe兼容问题_兼容解决 IE 、火狐、谷歌浏览器中 Iframe框架的页面缓存的方法...
  20. Linux内核源码 ---- el2_setup源码解析

热门文章

  1. 【CodeVS2226】飞行棋
  2. Android自动化测试之路——技术准备
  3. FZU_1683 矩阵快速幂 求和
  4. [ app.json 文件内容错误] app.json: [“usingComponents“][“van-button“]: “@vant/weapp/button/index“ 未找到
  5. LeetCode--85.最大矩形(单调栈)
  6. 机器学习实战13-卷积神经网络
  7. 7-234 两个有序序列的中位数 (25 分)
  8. R7-4 检查密码 (15 分)
  9. 使用函数输出水仙花数
  10. PTA21、K好数 (10 分)