请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
显然题目想实现链表的深拷贝,和传统的链表复制不同处在于,传统的简单链表只有val和next域,只要一边遍历一边新建节点连接即可。但random指针指向的节点位置不固定,可能在很后面遍历的时候该节点还未创建,所以需要一些新的处理。
略加思考之后我写出了一个笨方法:next指针的复制照常,同时用一个int数组记录每个节点的random域位置,最后再遍历一遍新链表将random域填上,如下所示。
public Node copyRandomList(Node head) {
Node dummy = new Node(-1);
Node dummyd = new Node(-1);
dummyd.next = dummy;
Node p = head;
int length = 0;
while(p!=null){
length++;
dummy.next = new Node(p.val);
p = p.next;
dummy = dummy.next;
}
int randomloc[] = new int[length+1];
int loc = 0;
p = head;
dummy = dummyd.next.next;
while(p!=null){
if(p.random==null){randomloc[loc] = -1;}
if(p.random == p){randomloc[loc] = -2;}
Node start = head;
int realloc = 0;
while(start!=p.random){
start = start.next;
realloc++;
}
randomloc[loc] = realloc;
loc++;
p = p.next;
}
p = head;
loc = 0;
while(dummy!=null){
if(randomloc[loc]==-1){
dummy.random = null;
}
else if(randomloc[loc]==-2){
dummy.random = dummy;
}
else{
Node start = dummyd.next.next;
int index = 0;
while(index!=randomloc[loc]){
start = start.next;
index++;
}
dummy.random = start;
}
dummy = dummy.next;
loc++;
}
return dummyd.next.next;
}
可想而知,该方法时间复杂度非常高,毕竟涉及到O(N²)级别的遍历。在阅读大佬题解后简单方法看得我五体投地:在遍历原链表的同时直接把新节点都连接在原链表上,每个旧节点后连一个val值相同的新节点。第一次遍历后得到一个扩大二倍的链表,再来一次遍历把每个新节点的random域补全:每个新节点的random域肯定是前一个节点(旧节点)的random域的next域(新的random)。最终将新旧链表拆分,返回新链表即可。思路实在厉害
class Solution {
public Node copyRandomList(Node head) {
if(head == null) return null;
Node cur = head;
// 1. 复制各节点,并构建拼接链表
while(cur != null) {
Node tmp = new Node(cur.val);
tmp.next = cur.next;
cur.next = tmp;
cur = tmp.next;
}
// 2. 构建各新节点的 random 指向
cur = head;
while(cur != null) {
if(cur.random != null)
cur.next.random = cur.random.next;
cur = cur.next.next;
}
// 3. 拆分两链表
cur = head.next;
Node pre = head, res = head.next;
while(cur.next != null) {
pre.next = pre.next.next;
cur.next = cur.next.next;
pre = pre.next;
cur = cur.next;
}
pre.next = null; // 单独处理原链表尾节点
return res; // 返回新链表头节点
}
}
作者:jyd
链接:https://leetcode-cn.com/problems/fu-za-lian-biao-de-fu-zhi-lcof/solution/jian-zhi-offer-35-fu-za-lian-biao-de-fu-zhi-ha-xi-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。