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.
Java Solution 1
We can solve this problem by doing the following steps:
- copy every node, i.e., duplicate every node, and insert it to the list
- copy random pointers for all newly created nodes
- break the list to two
public RandomListNode copyRandomList(RandomListNode head) { if (head == null) return null; RandomListNode p = head; // copy every node and insert to list while (p != null) { RandomListNode copy = new RandomListNode(p.label); copy.next = p.next; p.next = copy; p = copy.next; } // copy random pointer for each new node p = head; while (p != null) { if (p.random != null) p.next.random = p.random.next; p = p.next.next; } // break list to two p = head; RandomListNode newHead = head.next; while (p != null) { RandomListNode temp = p.next; p.next = temp.next; if (temp.next != null) temp.next = temp.next.next; p = p.next; } return newHead; } |
The break list part above move pointer 2 steps each time, you can also move one at a time which is simpler, like the following:
while(p != null && p.next != null){ RandomListNode temp = p.next; p.next = temp.next; p = temp; } |
Java Solution 2 – Using HashMap
From Xiaomeng’s comment below, we can use a HashMap which makes it simpler.
public RandomListNode copyRandomList(RandomListNode head) { if (head == null) return null; HashMap<RandomListNode, RandomListNode> map = new HashMap<RandomListNode, RandomListNode>(); RandomListNode newHead = new RandomListNode(head.label); RandomListNode p = head; RandomListNode q = newHead; map.put(head, newHead); p = p.next; while (p != null) { RandomListNode temp = new RandomListNode(p.label); map.put(p, temp); q.next = temp; q = temp; p = p.next; } p = head; q = newHead; while (p != null) { if (p.random != null) q.random = map.get(p.random); else q.random = null; p = p.next; q = q.next; } return newHead; } |
Please😻 next chapter fasttttt
Might be a bit more descriptive:
Node copyList(Node head)
{
if (head == null) return null;
// o2n - Orig to New
HashMap o2n = new HashMap();
Node newHead = new Node(head.value);
for (Node newNode = newHead, nextOrig = head.next ; nextOrig != null ; nextOrig = nextOrig.next)
{
Node nextNewNode = o2n.get(nextOrig);
// Circular list
if (nextNewNode != null) break;
nextNewNode = new Node(nextOrig.value);
newNode.next = nextNewNode;
o2n.put(nextNode, nextNewNode);
newNode = nextNewNode;
}
for (Node node = head ; node != null ; node = node.next)
{
Node newNode = o2n.get(node);
if (node.random == null) continue;
Node newRandom = o2n.get(node.random);
if (newRandom == null) throw new IllegalArgumentException(“Random doesn’t point to a node in the list.â€);
newNode.random = newRandom;
}
return newHead;
}
same as copying a list without random pointer, but before creating a new node check for presence in alreadyCreated map.
public RandomListNode copyRandomList(RandomListNode head) {
RandomListNode dummy = new RandomListNode(0);
RandomListNode prev = dummy;
//
Map alreadyCreated = new HashMap();
while(head != null){
RandomListNode newNode = alreadyCreated.containsKey(head) ? alreadyCreated.get(head) : new RandomListNode(head.label);
alreadyCreated.put(head,newNode);
newNode.random = head.random == null || alreadyCreated.containsKey(head.random) ? alreadyCreated.get(head.random) : new RandomListNode(head.random.label);
alreadyCreated.put(head.random,newNode.random);
prev.next = newNode;
prev = newNode;
head = head.next;
}
return dummy.next;
}
This is my solution
public RandomListNode copyRandomList(RandomListNode head)
{
Map nodesMap = new HashMap();
if(head == null)
return null;
RandomListNode first = head;
while(head != null)
{
RandomListNode node = new RandomListNode(head.label);
nodesMap.put(head,node);
head = head.next;
}
for(RandomListNode originalNode : nodesMap.keySet())
{
nodesMap.get(originalNode).next = nodesMap.get(originalNode.next);
nodesMap.get(originalNode).random = nodesMap.get(originalNode.random);
}
return nodesMap.get(first);
}
This is my solution: keep putting .random and next into HashMap, then we just need one iteration instead of two.
I also have the sames solutions. And I added another solution using recursion:
( url: http://traceformula.blogspot.com/2015/07/copy-list-with-random-pointers.html )
public class Solution {
public HashMap createdNode;
public RandomListNode copyRandomList(RandomListNode head) {
createdNode = new HashMap();
return cc(head);
}
private RandomListNode cc(RandomListNode node) {
if(node == null)
{
return null;
}
RandomListNode newNode = new RandomListNode(node.label);
createdNode.put(node, newNode);
newNode.next = cc(node.next);
//now assign the random pointer
RandomListNode newRandom = null;
if(node.random != null)
{
newRandom = createdNode.get(node.random);
}
newNode.random = newRandom;
return newNode;
}
}
> RandomListNode newhead=head;
This does not create a copy. Both p and q are references to the same list.
can’t we simply do this
p=head;
RandomListNode newhead=head;
q=newhead;
while(p.random!=null)
{
q.label=p.label;
q.random=p.random;
q=q.random;
p=p.random;
}
I really don’t see the point of having random and next as complementary fields for linkedlist. Correct me if I am wrong.
p.random is the node is the original list. Since newly added nodes are always the next to original nodes, so p.next.random = p.random.next;
http://algods-cracker.blogspot.in/2015/05/flipkart-question-clone-linked-list.html
This solution doesnot work if list has duplicate elements.
I have a question about this line: p.next.random = p.random.next;,
shouldn’t it be: p.next.random = p.random;
good solutions
That’s very nice solutions! The first might be very hard to think of if one were in the interview, it’s a little bit tricky, the second one is reasonable but with the cost of additional memory.
Okay, I see.
I just put my code in <pre> <code>, and Disqus changed them, I don’t know why 🙁 Maybe the “>” confused Disquz.
For first line, it should be HashMap < randomlistnode, randomlistnodepre > n2nMap = new HashMap < randomlistnode, randomlistnodepre >.
And for the second line, it should be not existed.
Good solution. Is this line legal?
HashMap n2nMap = new HashMap();
What about using hash map to store the original node reference to new node reference mapping?
My implementation is:
(1) first foreach node in list, copy it, store the original node to new node mapping in hashmap
(2)Still foreach node in original list, if its random attribute is not null, change the corresponding new node’s random attribute based on the hashmap.
Here is my code:
public RandomListNode copyRandomList(RandomListNode head) {
if(head ==null)
return null;
HashMap n2nMap = new HashMap();
RandomListNode newHead = new RandomListNode(head.label);
RandomListNode p = head;
RandomListNode q = newHead;
n2nMap.put(head, newHead);
p = p.next;
while(p != null){
RandomListNode temp = new RandomListNode(p.label);
n2nMap.put(p,temp);
q.next = temp;
q = temp;
p = p.next;
}
p = head;
q = newHead;
while(p!=null){
if(p.random != null)
q.random = n2nMap.get(p.random);
else
q.random = null;
p = p.next;
q = q.next;
}
return newHead;
}