35. 复杂链表的复制
链接
https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/
难度: #中等
题目
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例 1:
![](/assets/blank.gif)
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
![](/assets/blank.gif)
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
![](/assets/blank.gif)
输入: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. 复杂链表的复制相关推荐
- 【LeetCode】剑指 Offer 35. 复杂链表的复制
[LeetCode]剑指 Offer 35. 复杂链表的复制 文章目录 [LeetCode]剑指 Offer 35. 复杂链表的复制 package offer;import java.util.Ar ...
- 剑指 Offer 35. 复杂链表的复制
剑指 Offer 35. 复杂链表的复制 题目 题目链接 解题思路 题目理解 解题思路 具体代码 题目 题目链接 https://leetcode-cn.com/problems/fu-za-lian ...
- 剑指offer:面试题35. 复杂链表的复制
题目:复杂链表的复制 请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 ...
- 【三次优化】剑指 Offer 35. 复杂链表的复制
立志用最少代码做最高效的表达 请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意 ...
- 剑指offer——35复杂链表的复制
这题很是巧妙. 突破了常规思维. 竟然可以把传入进来的链表和复制的链表链在一起.然后再算出slibling指针.最后在分离. 直接把空间复杂度变为O(1)了. 很巧妙,很实用. 题目: 请实现函数Co ...
- 剑指 Offer 35. 复杂链表的复制(哈希/衍生拆分图解)
题目描述 请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null. ...
- LeetCode笔记】剑指 Offer 35. 复杂链表的复制(Java、哈希表、原地算法)
文章目录 题目描述 思路 && 代码 1. 哈希表法 2. 原地算法 二刷 题目描述 主要有两个考虑点: 不能改变原链表 新链表赋予 next.random 时,复制结点不一定存在 思 ...
- 【算法】剑指 Offer 35. 复杂链表的复制 【重刷】
1.概述 地址:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/ 请实现 copyRandomList 函数,复制一个复 ...
- 剑指offer面试题35. 复杂链表的复制(DFS)(深拷贝)
题目描述 请实现 copyRandomList 函数,复制一个复杂链表.在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null. ...
最新文章
- luogu P3393 逃离僵尸岛(点权最短路 + 多源BFS)
- 政府免费WiFi遭吐槽:近七成网友表示从未用过
- Java 面向对象:super关键字的理解
- 你真的会使用SQL Server的备份还原功能吗?之一:恢复模型
- SpringBoot 2.1.0 整合 WebSocket 通信
- 服务器cpu占用过高一般是什么原因,常见云服务器CPU占用100%问题原因及解决办法...
- 使用SPSS对数据异常值进行探索分析
- Python中pass是什么?
- iOS开发篇(二)自定义评分星级条RatingBar
- MFC radio button 设置默认选中
- 计算机在机械智能制造中的应用,机电一体化技术应用于智能制造中的优势研究...
- 玉米社:抖音账号被限流了怎么办?一步步教你解除限制
- 2018-8-28-win10-uwp-MVVM入门
- PMO如何有效搭建项目管理体系︱伯俊软件PMO经理李双燕
- 软件工程师,用100天时间让CSDN粉丝数从0狂飙到10000
- 初学者都会学习有关电控制图软件EPLAN的安装,下面有破解版本2.7,值得一看
- NGUI 中,长技能图标显示技能Tips的核心代码
- 日语中 “不得不”的6种表达,你都学会了吗?
- 谷歌浏览器iframe兼容问题_兼容解决 IE 、火狐、谷歌浏览器中 Iframe框架的页面缓存的方法...
- Linux内核源码 ---- el2_setup源码解析
热门文章
- 【CodeVS2226】飞行棋
- Android自动化测试之路——技术准备
- FZU_1683 矩阵快速幂 求和
- [ app.json 文件内容错误] app.json: [“usingComponents“][“van-button“]: “@vant/weapp/button/index“ 未找到
- LeetCode--85.最大矩形(单调栈)
- 机器学习实战13-卷积神经网络
- 7-234 两个有序序列的中位数 (25 分)
- R7-4 检查密码 (15 分)
- 使用函数输出水仙花数
- PTA21、K好数 (10 分)