随机链表的复制

随机链表的复制

复制随机链表

例题:leetcode138

这是一个深拷贝问题,单链表的复制很简单,真正麻烦的是random指针。

step1复制链表

有如图两种思路:

仔细思考:如果像上方一样分开复制为两个链表,那么在复制random指针是,每次复制一个random指针,就需要在新链表中进行一次遍历,

查找到新链表中对应random所指向的结点。所以遍历的次数会随着random指针的数量而增长,造成浪费。

核心问题:如何更快的搜索到新链表中与原链表random指针指向的结点值相同的结点。

例如假设原链表为1->2->3->4,其中1的random指向4 。那么在复制的新链表中,在复制1这个结点时,就需要去找到新链表中的4结点,这就需要进行一次遍历。造成了时间上的浪费。

那么再看看第二种复制方式(交叉复制)

图中红色部分是复制的新节点。如果使用这种方式进行复制,形成old-new-old-new-old-new的链表结构,就可以如下图更轻易地找到要复制的random指针指向的结点。

对应操作:

// 复制random指针

curr = head;

while (curr) {

// 如图中所示

if(curr->random){

curr->next->random = curr->random->next;

}

// curr 一步两跳保证curr在遍历旧链表

curr = curr->next->next;

}

到此已经完成了数据域和random指针的深拷贝。

step 2拆分链表

拆分的逻辑较为简单如图所示:

首先确认新旧头节点,curr从旧结点开始遍历,curr->next作为新链表的头节点。每次将curr指针指向其nextNode的后继。完成操作后将curr向后移动一个节点,直到curr的后继为空。

// 新旧链表的拆分

curr=head;

Node*newHead=head->next;

while(curr->next){

Node*nextNode=curr->next;

curr->next=nextNode->next;

//curr向后移动一位

curr=nextNode;

}

完整代码如下

class Solution {

public:

Node* copyRandomList(Node* head) {

if(head==nullptr){

return head;

}

Node* curr = head;

// 复制当前节点并插入当前节点的后方

// old-new-old-new-old-new

while (curr) {

Node* newNode = new Node(curr->val);

Node* nextNode = curr->next;

curr->next = newNode;

newNode->next = nextNode;

curr = nextNode;

}

// 复制random指针

curr = head;

while (curr) {

// 如图中所示

if(curr->random){

curr->next->random = curr->random->next;

}

// curr 一步两跳保证curr在遍历旧链表

curr = curr->next->next;

}

// 新旧链表的拆分

curr=head;

Node*newHead=head->next;

while(curr->next){

Node*nextNode=curr->next;

curr->next=nextNode->next;

curr=nextNode;

}

return newHead;

}

};

相关阅读