【问题描述】[中等]

【解答思路】

1. 暴力 直接复制

将链表从头节点一个一个复制下去,
在根据记录的总长度num,遍历原来的每个节点的random到尾节点个数count,然后顺序遍历找到新链表的该指针在num-count上 。
时间复杂度:O(N^2) 空间复杂度:O(N)

class Solution {public Node copyRandomList(Node head) {if(head==null) return head;Node newHead=new Node(head.val);Node keep=newHead;Node node=head.next;int num=1;//记录节点数while(node!=null){keep.next=new Node(node.val);node=node.next;keep=keep.next;num++;}keep.next=null;Node newn=newHead;Node oldn=head;//n r 定位randomNode n;Node r;int count;while (oldn!=null){n= oldn.random;//进行循环找到酒链表random指向的位置nr=newHead;count=0;//计算出旧链表n距离尾节点个数while (n!=null){n=n.next;count++;}//计算旧的random在链表中的位置  利用新旧链表新旧位置相同的原理for(int res=num-count;res>0;res--){r=r.next;}newn.random=r;//遍历新旧链表oldn=oldn.next;newn=newn.next;}return newHead;}
}作者:zhao-1z
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/javaliang-chong-xie-fa-by-zhao-1z/
2. HashMap O(N)空间


**时间复杂度:O(N) 空间复杂度:O(N) **

/*
// Definition for a Node.
class Node {public int val;public Node next;public Node random;public Node() {}public Node(int _val,Node _next,Node _random) {val = _val;next = _next;random = _random;}
};
*/
public class Solution {// Visited dictionary to hold old node reference as "key" and new node reference as the "value"HashMap<Node, Node> visited = new HashMap<Node, Node>();public Node getClonedNode(Node node) {// If the node exists thenif (node != null) {// Check if the node is in the visited dictionaryif (this.visited.containsKey(node)) {// If its in the visited dictionary then return the new node reference from the dictionaryreturn this.visited.get(node);} else {// Otherwise create a new node, add to the dictionary and return itthis.visited.put(node, new Node(node.val, null, null));return this.visited.get(node);}}return null;}public Node copyRandomList(Node head) {if (head == null) {return null;}Node oldNode = head;// Creating the new head node.Node newNode = new Node(oldNode.val);this.visited.put(oldNode, newNode);// Iterate on the linked list until all nodes are cloned.while (oldNode != null) {// Get the clones of the nodes referenced by random and next pointers.newNode.random = this.getClonedNode(oldNode.random);newNode.next = this.getClonedNode(oldNode.next);// Move one step ahead in the linked list.oldNode = oldNode.next;newNode = newNode.next;}return this.visited.get(head);}
}作者:LeetCode
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/fu-zhi-dai-sui-ji-zhi-zhen-de-lian-biao-by-leetcod/
3. HashMap O(N)空间

遍历第一遍链表,我们不考虑链表之间的相互关系,仅仅生成所有节点,然后把它存到 HashMap 中,h(val) 作为 key,Node 作为 value。

遍历第二遍链表,将之前生成的节点取出来,更新它们的 next 和 random 指针。

时间复杂度:O(N) 空间复杂度:O(N)

public Node copyRandomList(Node head) {if (head == null) {return null;}HashMap<Node, Node> map = new HashMap<>();Node h = head;while (h != null) {Node t = new Node(h.val); map.put(h, t);h = h.next;}h = head;while (h != null) {if (h.next != null) {map.get(h).next = map.get(h.next);}if (h.random != null) {map.get(h).random = map.get(h.random);}h = h.next;}return map.get(head);
}作者:windliang
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-32/
4. HashMap O(N)空间

只遍历一次链表。
核心思想就是延迟更新它的 next。

1 -> 2 -> 3
用 cur 指向已经生成的节点的末尾
1 -> 2
^
c
然后将 3 构造完成
最后将 2 的 next 指向 3
1 -> 2 -> 3
^
c
期间已经生成的节点存到 HashMap 中,第二次遇到的时候直接从 HashMap 中拿

时间复杂度:O(N) 空间复杂度:O(N)

public Node copyRandomList(Node head) {if (head == null) {return null;}HashMap<Node, Node> map = new HashMap<>();Node h = head;Node cur = new Node(-1); //空结点,dummy 节点,为了方便头结点计算while (h != null) {//判断当前节点是否已经产生过if (!map.containsKey(h)) {Node t = new Node(h.val);map.put(h, t);}//得到当前节点去更新它的 random 指针Node next = map.get(h);if (h.random != null) {//判断当前节点是否已经产生过if (!map.containsKey(h.random)) {next.random = new Node(h.random.val);map.put(h.random, next.random);} else {next.random = map.get(h.random);}}//将当前生成的节点接到 cur 的后边cur.next = next;cur = cur.next;h = h.next;}return map.get(head);
}
5. O(1)空间 (用原链表的 next 域保存新生成的节点)

主要解决的问题就是我们生成节点以后,当更新它的 random 的时候,怎么找到之前生成的节点,前两种解法用了 HashMap 全部存起来,这里的话可以利用原来的链表的指针域。

主要需要三步。

  1. 生成所有的节点,并且分别插入到原有节点的后边
  2. 更新插入节点的 random
  3. 将新旧节点分离开来

时间复杂度:O(N) 空间复杂度:O(1)

public Node copyRandomList(Node head) {if (head == null) {return null;}Node l1 = head;Node l2 = null;//生成所有的节点,并且分别插入到原有节点的后边while (l1 != null) {l2 = new Node(l1.val);l2.next = l1.next;l1.next = l2;l1 = l1.next.next;}//更新插入节点的 randoml1 = head;while (l1 != null) {if (l1.random != null) {l1.next.random = l1.random.next;}l1 = l1.next.next;}l1 = head;Node l2_head = l1.next;//将新旧节点分离开来while (l1 != null) {l2 = l1.next;l1.next = l2.next;if (l2.next != null) {l2.next = l2.next.next;}l1 = l1.next;}return l2_head;
}
/*
// Definition for a Node.
class Node {public int val;public Node next;public Node random;public Node() {}public Node(int _val,Node _next,Node _random) {val = _val;next = _next;random = _random;}
};
*/
public class Solution {public Node copyRandomList(Node head) {if (head == null) {return null;}// Creating a new weaved list of original and copied nodes.Node ptr = head;while (ptr != null) {// Cloned nodeNode newNode = new Node(ptr.val);// Inserting the cloned node just next to the original node.// If A->B->C is the original linked list,// Linked list after weaving cloned nodes would be A->A'->B->B'->C->C'newNode.next = ptr.next;ptr.next = newNode;ptr = newNode.next;}ptr = head;// Now link the random pointers of the new nodes created.// Iterate the newly created list and use the original nodes' random pointers,// to assign references to random pointers for cloned nodes.while (ptr != null) {ptr.next.random = (ptr.random != null) ? ptr.random.next : null;ptr = ptr.next.next;}// Unweave the linked list to get back the original linked list and the cloned list.// i.e. A->A'->B->B'->C->C' would be broken to A->B->C and A'->B'->C'Node ptr_old_list = head; // A->B->CNode ptr_new_list = head.next; // A'->B'->C'Node head_old = head.next;while (ptr_old_list != null) {ptr_old_list.next = ptr_old_list.next.next;ptr_new_list.next = (ptr_new_list.next != null) ? ptr_new_list.next.next : null;ptr_old_list = ptr_old_list.next;ptr_new_list = ptr_new_list.next;}return head_old;}
}
6. O(1)空间 (用原链表的 random域保存新生成的节点)

可以利用原链表的 random 域把新生成的节点保存起来。
主要还是三个步骤。

  1. 生成所有的节点,将它们保存到原链表的 random 域,同时利用新生成的节点的 next 域保存原链表的 random。
  2. 更新新生成节点的 random 指针。
  3. 恢复原链表的 random 指针,同时更新新生成节点的 next 指针。

时间复杂度:O(N) 空间复杂度:O(1)

public Node copyRandomList(Node head) {if (head == null) {return null;}Node l1 = head;Node l2 = null;//生成所有的节点,讲它们保存到原链表的 random 域,//同时利用新生成的节点的 next 域保存原链表的 random。while (l1 != null) {l2 = new Node(l1.val);l2.next = l1.random;l1.random = l2;l1 = l1.next;}l1 = head;//更新新生成节点的 random 指针。while (l1 != null) {l2 = l1.random;l2.random = l2.next != null ? l2.next.random : null;l1 = l1.next;}l1 = head;Node l2_head = l1.random;//恢复原链表的 random 指针,同时更新新生成节点的 next 指针。while (l1 != null) {l2 = l1.random;l1.random = l2.next;l2.next = l1.next != null ? l1.next.random : null;l1 = l1.next;}return l2_head;
}

【总结】

1.思路1暴力O(N^2)-> 思路2.3.4 HashMap O(N)->思路5.6 复制链表O(1)
2.链表操作的核心思想就是,在改变某一个节点的指针域的时候,一定要把该节点的指针指向的节点用另一个指针保存起来,以免造成丢失。
3.链表 画图

转载链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-32/
转载链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-32/

[剑指offer]面试题第[35]题[Leetcode][第138题][JAVA][复杂链表的复制][暴力][HashMap][复制链表]相关推荐

  1. 剑指Offer:面试题33——把数组排成最小的数(java实现)(未完待续)

    问题描述: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. 思路1: ...

  2. [剑指offer]面试题第[68-2]题[Leetcode][第236题][JAVA][二叉搜索树的最近公共祖先][递归]

    [问题描述][中等] 235/68-1 搜索二叉树 236/68-2 二叉树 [解答思路] 递归 时间复杂度:O(N) 空间复杂度:O(N) 情况 1. , 2. , 3. , 4. 的展开写法如下. ...

  3. [剑指offer]面试题第[57]题[Leetcode][第167题][JAVA][和为s的两个数字][两数之和][HashSet][二分][双指针]

    [剑指offer]面试题第[57]题[Leetcode][第167题][第1题] 有序无序之分 题目输出不同之分 以下解法按照[剑指offer]面试题第[57]题进行题解 [问题描述][简单] 输入一 ...

  4. 剑指offer——面试题35:第一个只出现一次的字符

    剑指offer--面试题35:第一个只出现一次的字符 Solution1: 垃圾算法不看也罢!自己想到的垃圾算法 class Solution { public:int FirstNotRepeati ...

  5. 算法题001 剑指Offer 面试题三:二维数组中的查找

    剑指Offer题目1:二维数组中的查找 题目描述: http://ac.jobdu.com/problem.php?cid=1039&pid=0 在一个二维数组中,每一行都按照从左到右递增的顺 ...

  6. 【剑指Offer面试题】 九度OJ1510:替换空格

    c/c++ 中的字符串以"\0"作为结尾符.这样每一个字符串都有一个额外字符的开销. 以下代码将造成内存越界. char str[10]; strcpy(str, "01 ...

  7. 剑指offer 面试题三 找出数组中重复的数字

    1 import org.junit.Test; 2 3 import java.util.Arrays; 4 import java.util.HashSet; 5 6 public class D ...

  8. (待补充)【n个骰子的点数】剑指offer——面试题43:n个骰子的点数

    剑指offer--面试题43:n个骰子的点数 [注意]此题再牛客网上没有OnlineJudge,在此补充解法. 题目:把n个骰子扔在地上,所有骰子朝上一面的点数之和为s.输入n,打印出s的所有可能的值 ...

  9. (补充)【打印1到最大的n位数】剑指offer——面试题12:打印1到最大的n位数

    剑指offer--面试题12:打印1到最大的n位数 此题在牛客网上没有OnlineJudge,在此补充两种做法. 参考网址:https://blog.csdn.net/yanxiaolx/articl ...

最新文章

  1. codeforces1027D
  2. java xsl生成word文件_导出生成xsl文件
  3. java itextsharp_使用 c#中的 itextsharp 以 pdf 格式填充 xml
  4. 【LeetCode - 122】买卖股票的最佳时机 II(贪心 或 dp)
  5. mysql etl工具有哪些_常见ETL工具一览,你知多少?
  6. 新增成功到编制为空bug_36 个JS 面试题为你助力,让面试更有力(面试必读)
  7. linux如何停止死循环脚本,Linux Shell教程(一)
  8. 记录一次json转换的经历
  9. oracle unlimit权限,有关UNLIMITED TABLESPACE权限
  10. 蓝牙---AVRCP协议
  11. 初中计算机excel考试系统,基于Excel构建计算机考试系统
  12. linux下安装mysql问题:mysqld_safe mysqld from pid file /usr/local/mysql/data/mysql.pid ended
  13. 支持个性化定制的酷玩多功能桌面充电器上手体验
  14. 在麒麟V10服务器上编译安装Storm
  15. alert angularjs
  16. 终于有人把智能语音处理讲明白了
  17. MyEclipse javaw.exe-没有软盘错误
  18. 《构建之法》第一次作业——阅读与准备工作
  19. ps批量修改名片文字_怎么修改图片上的文字 修改图片文字比如名片图片上面的地址需要修改下...
  20. 【数据分析】使用pandas和numpy分析美国大选献金项目

热门文章

  1. 基于Hibernate+spring的公司网站打造中(二)
  2. SecureCRT Application 已停止工作
  3. 芝麻信用综合评估未通过,请选择商户支持的其他方式使用服务
  4. Android 下拉式抽屉折叠动画
  5. 指定开始_Flink-Kafka指定offset的五种方式
  6. 华为手机记事本导出_深夜浅谈怎样用一部手机做电影解说?
  7. sklearn中的make_blobs的用法
  8. 使用SpringBoot AOP 记录操作日志、异常日志
  9. ribbon, restTemplate 负载均衡服务调用
  10. ADO.NET多值查询