题目
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
分析题目的难点在于随机指针的拷贝。
如下两种思路:
1. 利用map纪录原节点和拷贝节点的对应关系,纪录好后,再对指针赋值。有递归(解法1)和非递归(解法2)两种实现方法。
2. 比较巧妙的方法,只利用O(1)额外空间,遍历三次链表实现深度拷贝,具体方法参见解法3。
代码
解法1
import java.util.HashMap;
import java.util.Map;
public class CopyListWithRandomPointer {
class RandomListNode {
int label;
RandomListNode next, random;
RandomListNode(int x) {
this.label = x;
}
}
public RandomListNode copyRandomList(RandomListNode head) {
Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
map.put(null, null);
return solve(head, map);
}
public RandomListNode solve(RandomListNode head,
Map<RandomListNode, RandomListNode> map) {
if (map.containsKey(head)) {
return map.get(head);
}
RandomListNode node = new RandomListNode(head.label);
map.put(head, node);
node.next = solve(head.next, map);
node.random = solve(head.random, map);
return node;
}
}
解法2
import java.util.HashMap;
import java.util.Map;
public class CopyListWithRandomPointer {
class RandomListNode {
int label;
RandomListNode next, random;
RandomListNode(int x) {
this.label = x;
}
}
public RandomListNode copyRandomList(RandomListNode head) {
if (head == null) {
return null;
}
Map<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>();
RandomListNode newHead = new RandomListNode(head.label);
map.put(head, newHead);
RandomListNode p = head;
while (true) {
RandomListNode newP = map.get(p);
if (p.random != null) {
if (map.containsKey(p.random)) {
newP.random = map.get(p.random);
} else {
RandomListNode newRandom = new RandomListNode(
p.random.label);
map.put(p.random, newRandom);
newP.random = newRandom;
}
}
if (p.next != null) {
if (map.containsKey(p.next)) {
newP.next = map.get(p.next);
} else {
RandomListNode newNext = new RandomListNode(p.next.label);
map.put(p.next, newNext);
newP.next = newNext;
}
p = p.next;
continue;
}
break;
}
return newHead;
}
}
解法3
public class CopyListWithRandomPointer {
class RandomListNode {
int label;
RandomListNode next, random;
RandomListNode(int x) {
this.label = x;
}
}
public RandomListNode copyRandomList(RandomListNode head) {
if (head == null) {
return null;
}
// 1 pass: duplicate nodes one by one and link each after original one,
// thus building a list of 2*length.
RandomListNode p = head;
while (p != null) {
RandomListNode node = new RandomListNode(p.label);
node.next = p.next;
node.random = p.random;
p.next = node;
p = node.next;
}
// 2 pass: set random pointer of duplicated nodes to random.next which
// points to duplicated nodes.
p = head;
while (p != null) {
p = p.next;
if (p.random != null) {
p.random = p.random.next;
}
p = p.next;
}
// 3 pass: construct the new list by using only duplicated nodes.
p = head;
RandomListNode copyHead = head.next;
RandomListNode q = copyHead;
while (q.next != null) {
p.next = q.next;
q.next = q.next.next;
p = p.next;
q = q.next;
}
p.next = null;
return copyHead;
}
}