方法一:
/*
// 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;
}
}
*/
// 此方法使用hashmap进行原链表和新链表的节点映射
class Solution {
public Node copyRandomList(Node head) {
// 如果头节点为空,之间返回null
if(head == null) {
return null;
}
// 新建一个hashmap,存储原链表节点和新链表节点的映射关系,这样方便后续新链表的节点生成
Node cur = head;
Map<Node,Node> cache = new HashMap<>();
while(cur != null) {
cache.put(cur,new Node(cur.val));
cur = cur.next;
}
// cur移动节点回到head位置
cur = head;
// cur的next,也就是原链表的cur的下一个结点,赋值给了cur映射在新链表的next结点,random的情况也是一样,这样cur在原链表中移动结束,对应的映射节点也完成了每一次的复制,因此只需要获取原链表第一个节点head的映射即为新链表
while(cur != null) {
cache.get(cur).next = cache.get(cur.next);
cache.get(cur).random = cache.get(cur.random);
cur = cur.next;
}
return cache.get(head);
}
}
/*
// 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;
}
}
*/
// 此方法在原链表每个节点后复制一个一样的节点,最后只需要将复制的结点形成链表返回即可
class Solution {
public Node copyRandomList(Node head) {
// 头节点为空则返回空
if(head == null) {
return null;
}
Node cur = head;
// 遍历整个链表,在每个节点后面新增一个相同的节点
while(cur != null) {
// 取值
Node temp = new Node(cur.val);
// 新节点的next指向原有节点的下一个结点
temp.next = cur.next;
// 原有结点的next指向新节点
cur.next = temp;
// cur移动节点移动到新节点的下一个节点的位置
cur = temp.next;
}
// cur回到头节点的位置,再次遍历整个链表,将每个新节点的random指向每个原节点的random的next节点,因为原有节点的random所指向的节点和原有节点的random所指向的节点的下一个节点是一样的
cur = head;
while(cur != null) {
if(cur.random != null) {
cur.next.random = cur.random.next;
}
//因为有复制的节点存在,所以cur需要移动两次
cur = cur.next.next;
}
// cur移动到head的下一个节点,也就是新链表的第一个节点
cur = head.next;
// pre指向head
Node pre = head;
// res记录新链表的第一个节点位置
Node res = head.next;
// cur和pre同时每次指向下下个节点,并移动到自己指向的下个节点的位置
while(cur.next != null) {
pre.next = pre.next.next;
cur.next = cur.next.next;
pre = pre.next;
cur = cur.next;
}
// pre也指向空,保证原链表不变
pre.next = null;
return res;
}
}