1 题目
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.
Example 1:
Input:
{"$id":"1","next":{"$id":"2","next":null,"random":{"$ref":"2"},"val":2},"random":{"$ref":"2"},"val":1}
Explanation:
Node 1's value is 1, both of its next and random pointer points to Node 2.
Node 2's value is 2, its next pointer points to null and its random pointer points to itself.
2 尝试解
2.1 分析
给定一种特殊的链表,每个节点除了有指向后续节点的指针外,还有一个指针可以指向任意节点。要求复制此链表。简单的方法是,先按照顺序将每个节点及其后续指针复制一遍,同时用一个map保存原节点A到新节点A'的映射关系,即map[A]=A'。如果原节点A的任意指针指向了节点X,即A→random = X,则A'->random = X' = map[X] = map[A→random]。
这种方法需要遍历两遍原链表,时间复杂度为O(n)。同时需要额外的O(n)空间保存映射关系。
2.2 代码
class Solution {
public:
Node* copyRandomList(Node* head) {
Node* dummy = new Node(0,NULL,NULL);
Node* p = head;
Node* newp = dummy;
map<Node*,Node*> dict;
while(p != NULL){
Node* temp = new Node(p->val,NULL,NULL);//initial:1(p)->2 copy:0(newp) 1
newp->next = temp; //initial:1->2 copy:0->1
dict[p] = temp; //map the old node to the new node
p = p->next; //1->2(p), 0->1(newp)
newp = newp->next;
}
p = head;
newp = dummy->next;
while(p != NULL){ //old1->old2, dict = {old1:new1,old2:new2} new1->random = dict[old1->random]
newp->random = p->random!=NULL?dict[p->random]:NULL;
p = p->next;
newp = newp->next;
}
return dummy->next;
}
};
3 标准解
3.1 分析
进阶要求为不适用额外的空间。上述做法中额外空间用来存储原节点与新节点之间的关联,如果不使用额外空间,可以在创建新节点后,将新节点直接放在原节点之后,即A→A'→B→B'→C→C'。
在第二次遍历链表时,复制random指向关系。如果A→random = X,则A'→random = X' = X→next = A→random→next。
在第三遍遍历链表时,将原链表与新链表再拆开。
3.2 代码
public RandomListNode copyRandomList(RandomListNode head) {
RandomListNode iter = head, next;
// First round: make copy of each node,
// and link them together side-by-side in a single list.
while (iter != null) {
next = iter.next;
RandomListNode copy = new RandomListNode(iter.label);
iter.next = copy;
copy.next = next;
iter = next;
}
// Second round: assign random pointers for the copy nodes.
iter = head;
while (iter != null) {
if (iter.random != null) {
iter.next.random = iter.random.next;
}
iter = iter.next.next;
}
// Third round: restore the original list, and extract the copy list.
iter = head;
RandomListNode pseudoHead = new RandomListNode(0);
RandomListNode copy, copyIter = pseudoHead;
while (iter != null) {
next = iter.next.next;
// extract the copy
copy = iter.next;
copyIter.next = copy;
copyIter = copy;
// restore the original list
iter.next = next;
iter = next;
}
return pseudoHead.next;
}