给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。

要求返回这个链表的 深拷贝。 

我们用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-1);如果不指向任何节点,则为  null 。

链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer。
自己的题解:

思路:整两个MAP,一个用来存放原始的list中每个节点的地址对应的位置;一个用来存放第二个新的节点链表的每个位置(下标),对应的地址。

和这个视频的思路大致是一样的

 

然后,我自己的代码:

 

 

/*
// Definition for a Node.
class Node {
    int val;
    Node next;
    Node random;

    public Node(int val) {
        this.val = val;
        this.next = null;
        this.random = null;
    }
}
*/
import java.util.*;
class Solution {
    public Node copyRandomList(Node head) {
        
        Node HeadTemp=head;
        Node NodeList2Head=new Node(-1);
        Node NodeList2_ptr=NodeList2Head;


        int count=0;
        HashMap<Node, Integer> Map_ListNode_1 = new HashMap<>();//node 对应的第几个数
        HashMap<Integer,Node> Map_ListNode_2 = new HashMap<>();//第二个链表中用数 对应地址

        while(HeadTemp!=null)
        {
            Node NodeList2Temp=new Node(HeadTemp.val);
            // System.out.println(NodeList2Temp.val);
            NodeList2_ptr.next=NodeList2Temp;
            NodeList2_ptr=NodeList2_ptr.next;


            Map_ListNode_1.put(HeadTemp,count);
            Map_ListNode_2.put(count,NodeList2Temp);

            HeadTemp=HeadTemp.next;
            count++;
        }

        NodeList2_ptr.next=null;


        int count2=0;
        HeadTemp=head;
        NodeList2_ptr=NodeList2Head.next;

        while(HeadTemp!=null)
        {
            Integer pos_random_ptr=Map_ListNode_1.get(HeadTemp.random);
            // System.out.println("pos_random_ptr:"+pos_random_ptr);

            Node pos_node_adress=Map_ListNode_2.get(pos_random_ptr);
            // if(pos_node_adress!=null)
            // {
            //     System.out.println(pos_node_adress.val);
            // }
            NodeList2_ptr.random=pos_node_adress;

            // System.out.println("pos_node_adress val:"+pos_node_adress.val);

            // System.out.println(Map_ListNode_2.get(count2).val);
            NodeList2_ptr=NodeList2_ptr.next;
            HeadTemp=HeadTemp.next;
            count2++;
        }

        return NodeList2Head.next;

    }
}

Leetcode的题解(自己喜欢的):

方法 2: O(N)O(N) 空间的迭代
想法

迭代算法不需要将链表视为一个图。当我们在迭代链表时,我们只需要为 random 指针和 next 指针指向的未访问过节点创造新的节点并赋值即可。

算法

1.从 head 节点开始遍历链表。下图中,我们首先创造新的 head 拷贝节点。拷贝的节点如下图虚线所示。实现中,我们将该新建节点的引用也放入已访问字典中。

 

 

 

2.random 指针

如果当前节点 ii 的 random 指针指向一个节点 jj 且节点 jj 已经被拷贝过,我们将直接使用已访问字典中该节点的引用而不会新建节点。

如果当前节点 ii 的 random 指针指向的节点 jj 还没有被拷贝过,我们就对 jj 节点创建对应的新节点,并把它放入已访问节点字典中。

下图中, AA 的 random 指针指向的节点 CC 。前图中可以看出,节点 CC 还没有被访问过,所以我们创造一个拷贝的 C'C 节点与之对应,并将它添加到已访问字典中。

 

3.next 指针
如果当前节点 ii 的 next 指针指向的节点 jj 在已访问字典中已有拷贝,我们直接使用它的拷贝节点。
如果当前节点 ii 的next 指针指向的节点 jj 还没有被访问过,我们创建一个对应节点的拷贝,并放入已访问字典。

下图中,AA 节点的 next 指针指向节点 BB 。节点 BB 在前面的图中还没有被访问过,因此我们创造一个新的拷贝 B'B 节点,并放入已访问字典中。

 

 4.我们重复步骤 2 和步骤 3 ,直到我们到达链表的结尾。

 下图中, 节点 BB 的 random 指针指向的节点 AA 已经被访问过了,因此在步骤 2 中,我们不会创建新的拷贝,将节点 B'B ′的 random 指针指向克隆节点 A'A 同样的, 节点 BB 的 next 指针指向的节点 CC 已经访问过,因此在步骤 3 中,我们不会创建新的拷贝,而直接将 B'B ′的 next 指针指向已经存在的拷贝节点 C'C ′。

 

 

/*
// Definition for a Node.
class Node {
    public int val;
    public Node next;
    public Node random;

    public Node() {}

    public Node(int _val,Node _next,Node _random) {
        val = _val;
        next = _next;
        random = _random;
    }
};
*/
public class Solution {
  // Visited dictionary to hold old node reference as "key" and new node reference as the "value"
  HashMap<Node, Node> visited = new HashMap<Node, Node>();

  public Node getClonedNode(Node node) {
    // If the node exists then
    if (node != null) {
      // Check if the node is in the visited dictionary
      if (this.visited.containsKey(node)) {
        // If its in the visited dictionary then return the new node reference from the dictionary
        return this.visited.get(node);
      } else {
        // Otherwise create a new node, add to the dictionary and return it
        this.visited.put(node, new Node(node.val, null, null));
        return this.visited.get(node);
      }
    }
    return null;
  }

  public Node copyRandomList(Node head) {

    if (head == null) {
      return null;
    }

    Node oldNode = head;

    // Creating the new head node.
    Node newNode = new Node(oldNode.val);
    this.visited.put(oldNode, newNode);

    // Iterate on the linked list until all nodes are cloned.
    while (oldNode != null) {
      // Get the clones of the nodes referenced by random and next pointers.
      newNode.random = this.getClonedNode(oldNode.random);
      newNode.next = this.getClonedNode(oldNode.next);

      // Move one step ahead in the linked list.
      oldNode = oldNode.next;
      newNode = newNode.next;
    }
    return this.visited.get(head);
  }
}

作者:LeetCode
链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/fu-zhi-dai-sui-ji-zhi-zhen-de-lian-biao-by-leetcod/
来源:力扣(LeetCode)