最近在LeetCode上做了一道有一些难度的与链表相关的题目,现在分享给大家:
138. 复制带随机指针的链表https://leetcode.cn/problems/copy-list-with-random-pointer/
给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
最初我们看到这个题目的时候的思路可能是暴力的复制,进行多次的遍历,但是这不是一个非常好的方法,原链表中的随机指针不是很好复制。在这里,我们来介绍一种比较好的方法:我们可以在原链表的每一个结点之后都复制一个与其一样的结点,拷贝其数据然后插入到原来的链表内,如下图:
这样我们就可以很容易得到随机指针的指向。但是现在随机指针还是指向原链表,我们需要更新其随机指针,最后就是将新的链表从原链表中拆离出来,得到深拷贝后的链表。
上图就是将新链表拆离出来的过程,
struct Node* copyRandomList(struct Node* head) {
if (head == NULL)
{
return NULL;
}
struct Node* cur = head;
while (cur != NULL)
{
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
//新节点数据的拷贝
newnode->val = cur->val;
newnode->next =cur->next;
newnode->random = cur->random;
// if (cur->random != NULL)
// {
// newnode->random = cur->random->next;
// }
// else
// {
// newnode->random = cur->random;
// }
//节点数据的连接
cur->next = newnode;
//原节点的下一个节点
cur = newnode->next;
}
//更新随机指针
cur = head;
while (cur != NULL)
{
if (cur->random != NULL)
{
cur->random = cur->random->next;
}
else
{
cur->random = NULL;
}
cur = cur->next;
}
//重新链接新链表
struct Node* rehead = head->next;
struct Node* fast = head->next->next;
struct Node* slow = head->next;
while (fast != NULL)
{
//深拷贝节点连接
struct Node* _next = fast->next;
slow->next = fast->next;
fast = _next;
//
fast = fast->next;
slow = slow->next;
}
return rehead;
}