一、题目描述
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random
,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n
个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next
指针和 random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X
和 Y
两个节点,其中 X.random --> Y
。那么在复制链表中对应的两个节点 x
和 y
,同样有 x.random --> y
。
返回复制链表的头节点。
用一个由 n
个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index]
表示:
val
:一个表示Node.val
的整数。random_index
:随机指针指向的节点索引(范围从0
到n-1
);如果不指向任何节点,则为null
。
你的代码 只 接受原链表的头节点 head
作为传入参数。
示例:
二、题解
题目分析:
给定的链表节点包含三个部分:
class Node { int val; Node next; Node random; public Node(int val) { this.val = val; this.next = null; this.random = null; } }
(1)val:当前节点存储的值
(2)next:指向下一节点
(3)random:随机指针 ,可以指向链表中的任何节点或空节点。
复制这个随机链表,即每个新节点的值与其对应的原节点的值相同。新节点的 next
指针和 random
指针也都指向对应的新节点
思路分析:
若复制普通链表,我们只需遍历原链表,在遍历过程中创建新节点,再通过前驱节点prev指向当前新节点,即可实现普通链表的复制。而本题中新增了 random,由于 random 可以指向链表中任意节点或空节点,意味着我们不仅要实现 前驱节点对当前节点的指向,也要实现 前驱节点对随机节点的指向
我们可以利用哈希表,通过构建原链表节点与新链表节点的键值对映射关系来解决该题
具体实现:
(1)根据原链表节点的值创建新链表,并把原链表的节点和创建的新链表节点放入哈希表 map 中
(2)遍历原链表,根据原链表节点cur的next、random找到新链表节点node的next、random指向,并确定新链表的next、random
通过原链表节点找到新链表节点:map.get(cur),新链表节点的next:map.get(cur).next
通过原链表节点的next找到新链表节点的next:map.get(cur.next)
确定新链表的next:map.get(cur).next = map.get(cur.next)
通过原链表节点找到新链表节点:map.get(cur),新链表节点的random:map.get(cur).random
通过原链表节点的next找到新链表节点的random:map.get(cur.random)
确定新链表的random:map.get(cur).random = map.get(cur.random)
(3)返回新链表的头节点
通过原链表的头节点,找到新链表的头节点,并返回
代码实现:
class Solution { public Node copyRandomList(Node head) { //根据原链表创建新链表 Node cur = head; Map<Node,Node> map = new HashMap<>(); //遍历原链表,创建新链表,并将其放入map中 while(cur != null){ Node node = new Node(cur.val); map.put(cur,node); cur = cur.next; } //根据原链表节点的next、random修改新链表节点的next、random cur = head; while(cur != null){ map.get(cur).next = map.get(cur.next); map.get(cur).random = map.get(cur.random); cur = cur.next; } //返回新链表的头节点 return map.get(head); } }
题目来自: