思路一:首先我们先遍历链表,然后将链表先复制一次,并且使用 next 将他们连接起来,这样我们就得到了一个链表。其次我们需要将其 random 指针指向的节点连接到链表上面。首先我们可以考虑暴力的情况,我们遍历原始的链表,看看当前节点 random 指向的节点距离头结点有多少步,通过这个步数,我们就可以在复制的链表中找到这个节点,然后让当前节点的 random 指向我们找到的节点即可。时间复杂度
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if(pHead == null) return pHead;
RandomListNode clone = copy(pHead);
clone = findRandom(pHead, clone);
return clone;
}
public static RandomListNode findRandom(RandomListNode pHead, RandomListNode clone) {
RandomListNode curNode = pHead, curCloneNode = clone;
RandomListNode randomNode = pHead, randomCloneNode = clone;
while(curNode != null) {
int step = 0;
if(curNode.random != null) {//找到原始链表中的random指向的节点
while(randomNode != curNode.random) {
++ step;
randomNode = randomNode.next;
}
while(step > 0) {//找到复制链表中指向的节点
-- step;
randomCloneNode = randomCloneNode.next;
}
curCloneNode.random = randomCloneNode;
}
curNode = curNode.next;
curCloneNode = curCloneNode.next;
randomNode = pHead;
randomCloneNode = clone;
}
return clone;
}
public static RandomListNode copy(RandomListNode pHead) {//链表的复制
RandomListNode cur = pHead;
RandomListNode q = new RandomListNode(-1), ans = q;
while(cur != null) {
RandomListNode cloneNode = new RandomListNode(cur.label);
q.next = cloneNode;
q = q.next;
cur = cur.next;
}
return ans.next;
}
} 思路二:这种思路我们主要聚焦在怎么去优化找 random 指向的节点的。用下面的图来表示这种思路的一个存储方式:
按照上图,我们可以发现,如果把原节点和复制节点的关系使用 Map 存储起来,那么我们在进行 random 节点的复制的时候就可以直接根据 Map 中的数据来进行赋值,这个复杂度为 。
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
import java.util.*;
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if(pHead == null) return pHead;
Map<RandomListNode, RandomListNode> map = new HashMap<>();
RandomListNode cur = pHead;
while(cur != null) {//存储节点关系
RandomListNode cloneNode = new RandomListNode(cur.label);
map.put(cur, cloneNode);
cur = cur.next;
}
cur = pHead;
while(cur != null) {//根据关系复制链表
RandomListNode cloneNode = map.get(cur);
cloneNode.next = map.get(cur.next);
cloneNode.random = map.get(cur.random);
cur = cur.next;
}
return map.get(pHead);
}
} 思路三:在原链表中一次插入复制的节点,建立关系后拆分链表。这里要注意最后的返回,由于后台判题的机制,我们需要进行一定的处理,否则字符串输出的就是空串。
从上面的图可以看出来,我们不用使用Map就可以将其中的关系关联起来,进而进行一个复制,最后拆分这个链表即可。
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
import java.util.*;
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if(pHead == null) return null;
RandomListNode cur = pHead;
while(cur != null) {//向原链表中插入复制节点
RandomListNode cloneNode = new RandomListNode(cur.label);
cloneNode.next = cur.next;
cur.next = cloneNode;
cur = cloneNode.next;
}
cur = pHead;
while(cur != null) {//根据位置关系求出复制节点相应的random
if(cur.random != null) {
cur.next.random = cur.random.next;
}
cur = cur.next.next;
}
RandomListNode head = pHead.next;//拆分为两个链表
cur = pHead;//要使用这种方式来进行拆分,不然会出现空串的情况
while(cur.next != null) {
RandomListNode temp = cur.next;
if(temp != null) {
cur.next = temp.next;
cur = temp;
}
}
return head;//输出复制链表
}
} 
京公网安备 11010502036488号