这道题目的关键在于,每个节点还包含一个随机节点,随机地指向链表中的一个节点。我们不但要深度拷贝所有原链表的节点,还需要准确地让拷贝链表中随机节点的对应关系和原链表保持一致。假如我们先拷贝原链表,然后查找源链表中的随机节点对应关系,借此来拷贝随机节点。那么每个查找每个对应关系都需要付出 O ( n ) O(n) O(n)的时间复杂度。拷贝整个链表的随机节点关系就需要 O ( n 2 ) O(n^2) O(n2)的时间复杂度。
哈希表
先把节点全部复制一遍,并且将原节点和拷贝后的节点一一对应存储再哈希表中。再遍历一遍源链表和拷贝链表,根据哈希表查找拷贝节点中每个随机节点对应的节点。
用哈希表,一个非常丑的写法。
class Solution {
public Node copyRandomList(Node head) {
if(head == null)
return null;
Node src = head;
Node dstHead = new Node(src.val);
HashMap<Node, Node> map = new HashMap();
map.put(src, dstHead);
Node dstPtr = dstHead;
while(src.next != null){
dstPtr.next = new Node(src.next.val);
map.put(src.next, dstPtr.next);
dstPtr = dstPtr.next;
src = src.next;
}
dstPtr = dstHead;
src = head;
while(dstPtr != null){
dstPtr.random = map.get(src.random);
dstPtr = dstPtr.next;
src = src.next;
}
return dstHead;
}
}
来看看大佬的写法,多么漂亮。来源Krahets大神的题解。干净漂亮,太厉害了。
*/
class Solution {
public Node copyRandomList(Node head) {
Node src = head;
HashMap<Node, Node> map = new HashMap();
while(src != null){
map.put(src, new Node(src.val));
src = src.next;
}
src = head;
while(src != null){
map.get(src).next = map.get(src.next);
map.get(src).random = map.get(src.random);
src = src.next;
}
return map.get(head);
}
}
还有一种原地置换的方法,折磨了我一个小时。大致分为三个步骤
- 拷贝,使得原链表每个元素重复一遍
- 修改random节点
- 将原链表和拷贝链表分开。
/*
// 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;
Node src = head;
// 拷贝,使得链表每个元素重复一次
while(src != null){
Node temp = new Node(src.val);
// temp.random = src.random;
temp.next = src.next;
src.next = temp;
src = temp.next;
}
// 修改random节点
src = head;
while(src != null){
if(src.random != null)
src.next.random = src.random.next;
src = src.next.next;
}
src = head.next;
Node res = head.next; // 保存结果
Node prev = head; // 拆分得到原来链表
while(src.next != null){
// 注意,下面的语句不能写反,写反就GG了。
prev.next = prev.next.next;
src.next = src.next.next;
src = src.next;
prev = prev.next;
}
prev.next = null;
return res;
}
}