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.
The problem is to maintain the connection between the copy and its next, also the copy and its random pointer.
Say we have list 1->2->3->4.
If we want to construct the deep copy of only the next's pointer, without considering the random pointer, then we probably follow the procedure at our first thought:
cur = 1, make copy = 1
list: 1->2->3->4
copy: 1
cur = 2, make copy 2
list: 1->2->3->4
copy: 1->2
....
...
cur = 4, make copy 4
list: 1->2->3->4
list: 1->2->3->4
We create a new random pointer at node 1 and a new random pointer at node 2. Even though they are with the same value, they do not have the same address.
At final step we would have a copy of 1->2->3->4, where 3's next is 4. But at this time, 1's random node 3 would not link to node 4. Neither would 2's random node.
So when we construct random node for node 2, we should move 2's random pointer to 1's random pointer rather than making a new pointer.
So the problem would be how to remember the random pointer address, and how to move he random pointer to a previously created random pointer.
Solution 1: O(n^2)
First construct a copy list of the orginal list.
For current node A, we find the distance, d, between A's random pointer away and A in the original list. Then we come back to the copy list, link current node to the node with distance d away form it.
This is based on the assumption that in the copy list, distance between a node and its random pointer would be the same.
Code 1: naive copy
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
return naive_copy(head);
}
RandomListNode *naive_copy(RandomListNode *head){
RandomListNode * temp = new RandomListNode(0);
RandomListNode * pre = temp;
RandomListNode * cur = head;
while(cur){
pre->next = new RandomListNode(cur->label);
pre = pre->next;
cur = cur->next;
}
pre = temp->next;
cur = head;
while(pre && cur){
RandomListNode *r = cur->random;
if(rand){
RandomListNode *pre_fast = pre;
RandomListNode *cur_fast = cur;
while(cur_fast != r){
if(!cur_fast){
cur_fast = head;
pre_fast = temp->next;
}
else{
cur_fast = cur_fast->next;
pre_fast = pre_fast->next;
}
}
pre->random = pre_fast;
}
cur = cur->next;
pre = pre->next;
}
return temp->next;
}
};
Solution 2:
We use a map to store a node and its copy. map[node] = its copy
When a node A has random pointer to node B, point A copy's random pointer (map[nodeA]->random) to A's random pointer's copy (map[ node A's random pointer]).
Code:
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
return copy(head);
}
RandomListNode *copy(RandomListNode *head){
if(!head) return NULL;
map<RandomListNode*, RandomListNode*> mapp;
RandomListNode *cur = head;
mapp[head] = new RandomListNode(head->label);
while(cur){
//link current node's copy with its next
if(cur->next){
if(mapp.find(cur->next) == mapp.end())
mapp[cur->next] = new RandomListNode(cur->next->label);
mapp[cur]->next = mapp[cur->next];
}
//construct current node's copy with its random
if(cur->random){
if(mapp.find(cur->random) == mapp.end())
mapp[cur->random] = new RandomListNode(cur->random->label);
mapp[cur]->random = mapp[cur->random];
}
cur = cur->next;
}
return mapp[head];
}
};