题目
给你一个长度为 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 作为传入参数。
示例 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]]
提示:
- 0 <= n <= 1000
- -104 <= Node.val <= 104
- Node.random 为 null 或指向链表中的节点。
解题思路
前置知识
Map
Map集合存储元素是成对出现的,Map集合的键是唯一的,每个键最多只能映射到一个值。 不同键映射的值是可重复的。
注意:Map集合的数据结构是针对键有效,跟值无关。而Collection集合的数据结构是针对元素有效。
Map集合的功能概述
1: 添加功能
V put(K key,V value):添加元素。
如果键是第一次存储,就直接存储元素,返回null;
如果键不是第一次存储,就用值把以前的值替换掉,返回以前的值。
2: 删除功能
void clear():移除所有的键值对元素。
V remove(Object key):根据键删除键值对元素,并把值返回。
3: 判断功能
boolean containsKey(Object key):判断集合是否包含指定的键
boolean containsValue(Object value):判断集合是否包含指定的值
boolean isEmpty():判断集合是否为空
4: 获取功能
Set keySet():获取集合中所有键的集合
V get(Object key):根据键获取值
Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
Collection values():获取集合中所有值的集合
5: 长度功能
int size():返回集合中的键值对的总数
1.题目要求我们做深拷贝,也就是返回复制后的链表,但是链表中存在一个random指针指向随意的节点,所以我们并不能按顺序去复制链表,因为random指针可能会指向我们还未复制的节点,这个时候我们就要采用hashMap来辅助我们解决这个问题
2.首先我们创建一个hashMap来存放(原节点,新节点),然后我们利用for循环每次循环时创建一个新节点,让它的值等于原节点,然后将他俩一起放入hashMap中
3.我们再次使用for循环对哈市Map进行遍历,令新节点的next值等于原节点的next值( nodeMap.get(x).next = nodeMap.get(x.next)),以及令新节点的random值等于新节点的random值(nodeMap.get(x).random = nodeMap.get(x.random)),最后我们返回新链表的头节点即可( return nodeMap.get(head))
代码实现
class Solution {
public Node copyRandomList(Node head) {
//边界
if (head == null){
return null;
}
//遍历原链表,构造新链表的节点,存储在Map中
//Map<原链表节点,新链表节点>
//原1 => 新1
Map<Node,Node> nodeMap = new HashMap<>();
for (Node x = head ; x != null; x = x.next){
//构造新链表的节点
Node node = new Node(x.val);
nodeMap.put(x,node);
}
//对新链表进行链接操作
//原1.next和新1.next一一对应
//原1.random和新1.random一一对应
//原1.next = 原3 => 新1.next = 新3(这个地址就可以根据原3来取得)
for (Node x = head; x != null; x = x.next){
//新链表的random和next和原链表一一对应
//对于Map来说,key都是原链表的节点
//原1.next = 原3
nodeMap.get(x).next = nodeMap.get(x.next);
//原1.random = 原5
nodeMap.get(x).random = nodeMap.get(x.random);
}
//返回新链表的头节点,就是原链表的head的映射
return nodeMap.get(head);
}
}