LeetCode原题地址:剑指 Offer 35. 复杂链表的复制
思路:先复制next,再复制random
/*
// 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;
}
// 新链表的第一个结点的前一个结点,复制过程中需要使用,返回的是newHead.next
Node newHead = new Node(-1);
newHead.next = null;
newHead.random = null;
// 一个尾指针指向新链表的尾部,正向建链表过程中需要用到
Node newTail = newHead;
Node temp = head;
// 本次遍历只复制next域,相当于正向建立链表的过程
while (temp != null) {
Node node = new Node(temp.val);
node.next = null;
node.random = null;
newTail.next = node;
newTail = node;
temp = temp.next;
}
// 重新让temp指向head位置,下面的遍历过程需要原链表和新链表同时遍历同样的位
// 置(即两个指针各自指向自己的第一个、第二个,一直遍历到最后一个结点)
temp = head;
Node keyTemp = newHead.next;
while (temp != null && keyTemp != null) {
// 一个标志,用于标记当前访问结点的random域是指向了当前链表的其他结点还是null
boolean flag = false;
int count = 0;
// 如果当前结点的random域不是null,那么count用来记录random域指向了当前链表的第几个结点
if (temp.random != null) {
flag = true;
count = 0;
Node newTemp = head;
// 从头遍历原链表,找到当前结点random域指向的位置
while (newTemp != null) {
count++;
if (newTemp == temp.random) {
break;
}
newTemp = newTemp.next;
}
}
// 根据flag标记的不同,复制新链表中对应结点的random域时做不同的操作
// flag为true,那么需要找到新链表中的第count个结点,并把新链表中当前结点对应结点的random域指向该结点
if (flag) {
int cnt = 0;
Node curRandom = newHead.next;
while (curRandom != null) {
cnt++;
if (cnt == count) {
break;
}
curRandom = curRandom.next;
}
keyTemp.random = curRandom;
} else { // flag为false,那么新链表中当前结点对应结点的random域为null
keyTemp.random = null;
}
temp = temp.next;
keyTemp = keyTemp.next;
}
return newHead.next;
}
}