牛客链接
普通链表的深拷贝只需要通过遍历原链表一次就能实现,但是题目给出的复杂链表多了random指针,会跳跃性的指向任意节点,这让我们无法通过一次遍历解决这个问题。
利用HashMap建立映射
提前存储新节点对应哪个原节点,这样就能够找到新节点的random指针应该指向哪(指向原节点的random指针指向的节点的对应新节点)。
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
import java.util.HashMap;
public class Solution {
public RandomListNode Clone(RandomListNode pHead)
{
if (pHead == null) return null;
// 1. 建立<原节点, 新节点>的映射
HashMap<RandomListNode, RandomListNode> map = new HashMap<>();
RandomListNode cur = pHead;
while (cur != null) {
map.put(cur, new RandomListNode(cur.label));
cur = cur.next;
}
// 2. 根据映射关系,设置每个节点的两个指针
cur = pHead;
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(pHead);
}
}
需要遍历链表两次O(n),且需要建立辅助map,O(n)。
不使用额外空间
看注释。
/*
// Definition for a Node.
class Node {
int val;
Node next;
Node random;
public Node(int val) {
this.val = val;
this.next = null;
this.random = null;
}
}
*/
class Solution {
public Node copyRandomList(Node head) {
if (head == null) return null;
// 不使用辅助空间map
// 1. 将原始链表构造成A->A'->B->B'->...的形式
Node cur = head;
while (cur != null) {
Node newNode = new Node(cur.val);
newNode.next = cur.next;
cur.next = newNode;
cur = cur.next.next;
}
// 2. 设置新节点(A', B', C', ...)的random指针(主要目的)
// 跟Map异曲同工,Map是保存映射关系,而这个直接就让两个对应的节点挨着,方便找到自己的random
cur = head;
while (cur != null) {
// ×空指针判断
if (cur.random != null)
cur.next.random = cur.random.next;
cur = cur.next.next;
}
// 3. 将这个组合链表拆分开来,奇数位置是原始链表,偶数位置是新链表(从1开始)
Node pre = head;
cur = head.next;
Node newHead = head.next;
while (cur.next != null) {
pre.next = pre.next.next;
cur.next = cur.next.next;
pre = pre.next;
cur = cur.next;
}
// 此时pre.next仍然连接到cur,需要设置为pre.next.next即为null
pre.next = null;
return newHead;
}
}
不使用额外空间,时间复杂度仍然为O(n)。