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

1. 题目

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

2. 示例

示例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 

3. 题解

本题给出了两种解题思路:

  • HashMap
    • 建立Hash表,key为原节点,value为新节点。
    • 在Hash表中遍历key,就可以不断的获取新节点: map.get(cur)。让其next指向map.get(cur.next)节点即可,同样的,让random指向map.get(cur.random)即可。
    • 返回map.get(head)就是返回的新链表的头结点。
  • 拼接+拆分
    • 需要遍历三次
    • 第一次遍历建立拼接链表:原节点1->新节点1->原节点2->新节点2,这样的拼接链表。此时还未引入random。
    • 第二次遍历建立random指向:始终存在一个顺序,就是新节点的next一定在原节点中next指向的next节点的后面,新节点的random一定在原节点random指向的andom节点的后面。 
    • 第三次遍历拆分拼接年链表

4. 实现

4.1 HashMap

剑指 Offer 35. 复杂链表的复制
 1 public class CopyRandomList35 {
 2     // HashMap
 3     public Node copyRandomListA(Node head) {
 4         if(head == null) return null;
 5         Node cur = head;
 6         // HashMap<Key, value>,key:原节点,value:新节点。
 7         Map<Node, Node> map = new HashMap<>();
 8         // 遍历各节点,简历“原节点->新节点”的Map映射
 9         while (cur != null) {
10             map.put(cur, new Node(cur.val));
11             cur = cur.next;
12         }
13         cur = head;
14         // 遍历map,建立新链表
15         while (cur != null) {
16             map.get(cur).next = map.get(cur.next);
17             map.get(cur).random = map.get(cur.random);
18             cur = cur.next;
19         }
20         // 返回新链表的头结点
21         return map.get(head);
22     }
23 }
View Code

4.2 拼接+拆分

剑指 Offer 35. 复杂链表的复制
 1 public class CopyRandomList35 {
 2     // 拼接+拆分
 3     public Node copyRandomListB(Node head) {
 4         // 如果为空,直接返回
 5         if(head == null) return null;
 6         Node cur = head;
 7         // 1. 第一轮遍历,建立只包含next的拼接链表
 8         // 新链表结构:原节点1->新节点1->原节点2->新节点2
 9         while (cur != null) {
10             Node temp = new Node(cur.val);
11             temp.next = cur.next;
12             cur.next = temp;
13             cur = temp.next;
14         }
15         // 2. 第二轮遍历,建立random指向
16         cur = head;
17         while (cur != null) {
18             // 原节点的random不为Null,说明存在,那么新节点的random需要指向原节点的random的下一个节点。
19             if(cur.random != null) {
20                 cur.next.random = cur.random.next;
21             }
22             cur = cur.next.next;
23         }
24         cur = head.next;
25         Node pre = head, res = head.next;
26         // 3. 第三轮遍历,拆分链表
27         while(cur.next != null) {
28             pre.next = pre.next.next;
29             cur.next = cur.next.next;
30             pre = pre.next;
31             cur = cur.next;
32         }
33         pre.next = null;
34         return res;
35     }
36 }
View Code

5. 结语

  努力去爱周围的每一个人,付出,不一定有收获,但是不付出就一定没有收获! 给街头卖艺的人零钱,不和深夜还在摆摊的小贩讨价还价。愿我的博客对你有所帮助(*^▽^*)(*^▽^*)!

  如果客官喜欢小生的园子,记得关注小生哟,小生会持续更新(#^.^#)(#^.^#)。

 

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

上一篇:Matlab常用命令和数学符号表示


下一篇:vue配置elint自动修复