题目意思就是说给你给head 的Node节点(这是一个比较特殊的链表),来拷贝出它地结构出来。
方法一:借助HashMap的特性,定义一个HashMap<Node,Node> map对象,key和value都是value类型 ,key来存旧的链表,value来存新的链表。最后利用老节点和新节点的对应关系来实现一个拷贝新的链表。
对于理解哈希表的同学来说,应该不难理解,code也比较容易:
 /* 方法一:借助HashMap,定义一个HashMap<Node,Node> map对象,key和value都是value类型 */
 public static Node copyListWithRandom1(Node head) {
 HashMap<Node, Node> map = new HashMap<Node, Node>();
 Node cur = head;
 /* 将单链表的所有节点和value对应放进去map对象中 */
 while (cur != null) {
 map.put(cur, new Node(cur.value));// 这里新建一个节点,这个节点放head的value
 cur = cur.next;
 }
 /* 重新构建链表的结构,注意,此时map对象为map<cur,cur'>,cur'为新建立的节点 */
 cur = head;
 /*
  * 为了让大家更好的理解,我们假设旧节点和旧节点的next还有旧节点rand分别为cur,curJiu,curRand
  * (不懂的同学可以先去了解一下hashMap特点)所以有:cur.next= curJiu,cur.rand= curRand
  * 因此,为了保持这种结构,就有了(map.get(cur)).next = map.get(cur.next),rand同理。
  */
 while (cur != null) {
 map.get(cur).next = map.get(cur.next);
 map.get(cur).rand = map.get(cur.rand);
 cur = cur.next;
 }
 return map.get(head);
}
方法2:空间复杂度为O(1),只需要几个变量就可以实现,(不过个人觉得还是方法1更方便)不多说了,直接附上图:
编程如下:
 /*这个方法空间复杂度为O(1),并且不用用到哈希表,相对来说容易了许多,不过思路比较巧妙,主要就是三步走*/
 public static Node copyListWithRandom2(Node head) {
 if (head == null) {
 return null;
 }
 /* copy node and link to every node*/
 /*从之前的1 2 3 4 5 6
  *     6 6 5 3 - 4
  * 变为现在的1 1 2 2 3 3 4 4 5 5 6 6 
  *    6 - 6 - 5 - 3 - - - 4 -
  * 说到底就是添加了next指针,而rand指针不变*/
 Node next = null;
 Node cur = head; //每个新的操作之前都要对cur赋值
 while (cur != null) {
 next = cur.next; //先保存这个节点,同时也为了下面的移动方便
 cur.next = new Node(cur.value);
 cur.next.next = next;
 cur = next;//这里千万要注意,它要往前移动
 }
 
 /*set copy node rand
  * 也就是根据rand来设置新的链表的rand指针
  * 从之前的1 2 3 4 5 6
  *       6 6 5 3 - 4
  * 变为现在的1 1 2 2 3 3 4 4 5 5 6 6 
  *    6 6 6 6 5 5 3 3 - - 4 4
  * 说到底就是添加了rand指针*/
 cur = head; //每个新的操作之前都要对cur赋值
 Node curcopy = null;
 while (cur != null) {
 curcopy = cur.next;
 /*这里要先判断cur.rand存不存在*/
 if (cur.rand != null) {
 curcopy.rand = cur.rand.next;
 }
 next = cur.next.next;
 cur = next; //这里千万要注意,它要往前移动
 }
 
 /*split,将新建的链表和旧链表分离
  * 断开新链表和旧链表的连接*/
 cur = head; //每个新的操作之前都要对cur赋值
 Node res = head.next;  //定义这个节点是为了方便返回
 while (cur != null) {
 next = cur.next.next;  
 curcopy = cur.next;
 cur.next = next;
 /*这里要先判断curcopy.next存不存在*/
 if (next != null) {
 curcopy.next = next.next;
 } else {
 curcopy.next = null;
 }
 cur = next;//这里千万要注意,它要往前移动
 }
 return res;
 }