Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
一、题目描述
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
示例
示例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 <= 10000Node.random为空(null)或指向链表中的节点。- 节点数目不超过 1000 。
难度:中等
复杂链表的复制,链表结构确实复杂,题目不太好理解,看用例数量、又带图就能说明问题。
二、思路分析
众所周知,力扣上,简单题是真简单,中等题有些困难,困难题看不懂答案。
题目解析
- 复杂链表的复制,题目给到的链表结点比常规链表结点多了一个 random 结点,而这个结点是无序的,并且根据链表的特点,next 指针的走向不可逆,即无法再找到已经走过的结点。
- 基于上述问题,在复制结点时,不仅要复制当前结点的 next 结点和 random 结点,并且需要记录新旧结点的关系,以便在其他结点指向该结点时能够对应指向复制的新结点。
- 综上,在遍历链表结点时考虑 next 和 random 结点指向,并将当前结点和复制新结点关系存储在 map 中,在每次关联 next 和 random 结点时判断 map 中是否已经存在,存在则直接使用,不存在则复制后添加到 map。
解题思路
对于复杂链表的复制,具体实现流程为:
- 初始化 map 容器用来存放新旧结点对应关系,其中原始结点作为 key,新结点作为 value;
- 将 head 结点复制到新结点,并将关联关系加入到 map 中;
- 从 head 开始遍历整个整个链表,并在遍历过程中进行如下操作:
- 对于 next 指向结点
- 如果为 null,则复制结点指向 null;
- 如果非 null,则判断 map 中是否存在指向结点,存在则复制结点指向 map 中对应的value;如果不存在,则指向新复制结点,并将旧-新关系加入到 map 容器。
- 对于 random 指向结点操作方式与 next 一致
- 操作完成后,新旧链表中的当前结点指针都前进一步,继续进行遍历迭代操作
- 对于 next 指向结点
- 遍历完整个链表之后,map 中 head 结点对应的 value 就是新链表的头节点,返回即可。
三、AC 代码
- 代码定义类结构说明
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
实现代码
public Node copyRandomList(Node head) {
if(head == null) return null;
//使用集合存放每个操作过的结点,用于在random 时直接指向
HashMap<Node,Node> map = new HashMap<>();
Node result = new Node(head.val);
Node cur = result;
map.put(head,result);
while(head != null){
//next结点
Node next = head.next;
if(next == null){
cur.next = null;
}else if(map.containsKey(next)){
cur.next = map.get(next);
}else{
cur.next = new Node(next.val);
map.put(next,cur.next);
}
//random节点
Node random = head.random;
if(random == null){
cur.random = null;
}else if(map.containsKey(random)){
cur.random = map.get(random);
}else{
cur.random = new Node(random.val);
map.put(random,cur.random);
}
head = head.next;
cur = cur.next;
}
return result;
}
执行结果
四、总结
知识点
- 容器 map 中 key、value 都是链表结点,因此在比较是否相等时直接使用 == 来比较结点为同一个对象
最后
阳春三月,算法刷起来!LeetCode 剑指 Offer。