LeetCode 138. 随机链表的复制
给你一个长度为 n
的链表,每个节点包含一个额外增加的随机指针 random
,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n
个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next
指针和 random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X
和 Y
两个节点,其中 X.random --> Y
。那么在复制链表中对应的两个节点 x
和 y
,同样有 x.random --> y
。
返回复制链表的头节点。
用一个由 n
个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index]
表示:
val
:一个表示Node.val
的整数。random_index
:随机指针指向的节点索引(范围从0 到 n-1
);如果不指向任何节点,则为null
。
你的代码 只 接受原链表的头节点 head 作为传入参数。
迭代 + 节点拆分
思路及算法:
此处的难点就是如何 copy
深拷贝的节点的 random
?
思路是:将 copy
的节点依次插入到相应节点的后面,从而保证 copy
与相应的节点保持联系,而要找 copy
的节点的 random
就是先找到与 copy
对应的节点的 random
,而 random
的 next
就是 copy
节点的 random
,因为 copy
节点是对应节点的后一个节点,故 copy
节点的 random
就是对应节点的后一个,它们对应的位置是不变的,copy
节点总是对应节点的后一个位置这里可以理解为假设你目前是一个单身狗,你想要找一个女朋友,而你的好兄弟有女朋友这时,你通过你跟你好兄弟的这层关系就可以去找好兄弟的女朋友把他的闺蜜介绍给你。
- 我们首先将该链表中每一个节点拆分为两个相连的节点,例如对于链表
A→B→C
,我们可以将其拆分为A→A′→B→B′→C→C′
。
对于任意一个原节点S
,其拷贝节点S′
即为其后继节点。- 这样,我们可以直接找到每一个拷贝节点
S′
的随机指针应当指向的节点,即为其原节点S
的随机指针指向的节点T
的后继节点
T′
。需要注意原节点的随机指针可能为空,我们需要特别判断这种情况。- 当我们完成了拷贝节点的随机指针的赋值,我们只需要将这个链表按照原节点与拷贝节点的种类进行拆分即可,只需要遍历一次。同样需要注意最后一个拷贝节点的后继节点为空,我们需要特别判断这种情况。
struct Node* copyRandomList(struct Node* head) {
if(head==NULL)
{
return NULL;
}
//1.复制对应的链表节点,并连接在相应链表节点的后面
struct Node* cur = head;
while(cur)
{
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
newnode->val = cur->val;
newnode->next = cur->next;
cur->next = newnode;
cur = newnode->next;
}
//2.处理复制链表节点的random
cur = head;
while(cur)
{
if(cur->random)
cur->next->random = cur->random->next;
else
cur->next->random = NULL;
cur = cur->next->next;
}
//3.将原链表和复制链表拆分开,返回复制链表的头节点
struct Node* newhead = head->next;
struct Node* newcur = newhead;
head->next = head->next->next;
cur = head->next;
while(cur)
{
newcur->next = newcur->next->next;
newcur = newcur->next;
cur->next = cur->next->next;
cur = cur->next;
}
newcur->next = NULL;
return newhead;
}