LeetCode – Copy List with Random Pointer

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:

  1. copy every node, i.e., duplicate every node, and insert it to the list
  2. copy random pointers for all newly created nodes
  3. 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;
}
Category >> Algorithms  
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:
<pre><code> 
String foo = "bar";
</code></pre>

  1. xmpy on 2014-2-23

    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;
    }

  2. ryanlr on 2014-2-24

    Good solution. Is this line legal?


    HashMap n2nMap = new HashMap();

  3. Xiaomeng Zhao on 2014-2-24

    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.

  4. ryanlr on 2014-2-24

    Okay, I see.

  5. Kartrace on 2014-3-8

    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.

  6. zhou2214 on 2014-9-13

    good solutions

  7. Wilson Ziyou Zheng on 2015-2-9

    I have a question about this line: p.next.random = p.random.next;,
    shouldn’t it be: p.next.random = p.random;

  8. Parag Chaudhari on 2015-2-11

    This solution doesnot work if list has duplicate elements.

  9. Cracker on 2015-5-21
  10. Alyssa Chen on 2015-5-31

    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;

  11. Monica Shankar on 2015-6-27

    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.

  12. nuurtila on 2015-6-29

    > RandomListNode newhead=head;
    This does not create a copy. Both p and q are references to the same list.

  13. traceformula on 2015-7-3

    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;

    }

    }

  14. Roderick Gao on 2015-10-7

    This is my solution: keep putting .random and next into HashMap, then we just need one iteration instead of two.

  15. Ranjith Sompalli on 2016-6-3

    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);
    }

  16. Milan on 2016-9-4

    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;
    }

Leave a comment

*