https://leetcode.cn/problems/copy-list-with-random-pointer/
给你一个长度为 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
作为传入参数。
示例 1:
输入:head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出:[[7,null],[13,0],[11,4],[10,2],[1,0]]
示例 2:
输入:head = [[1,1],[2,1]]
输出:[[1,1],[2,1]]
示例 3:
输入:head = [[3,null],[3,0],[3,null]]
输出:[[3,null],[3,0],[3,null]]
提示:
0 <= n <= 1000
-104 <= Node.val <= 104
Node.random
为 null
或指向链表中的节点。这个题目的意思就是拷贝一份复杂链表,难点在于它的random指针所指向的空间与拷贝下来的链表之间缺少一种联系,当然可以用遍历链表的方式通过value去找那块空间,不过时间复杂度太高.
所以这道题的重中之重就是怎样让拷贝链表地random和原链表以及之间产生联系
我们不妨引入这样一种方法,在原链表每个节点的后面创建一个新的节点,该节点的值与上个节点相同,这样我们新节点的random指向的空间就是原节点的random指向空间的下一块空间,最后再将新节点从原链表中截下来,并恢复原链表.
/**
* Definition for a Node.
* struct Node {
* int val;
* struct Node *next;
* struct Node *random;
* };
*/
typedef struct Node Node;
struct Node* copyRandomList(struct Node* head) {
Node* pcur = head;
//在每个节点后面再插入一个相同的节点
while(pcur)
{
Node* copy = (Node*)malloc(sizeof(Node));
copy->val = pcur->val;
copy->next = pcur->next;
pcur->next = copy;
pcur = pcur->next->next;
}
pcur = head;
//处理random指针指向的节点(copy->random == pcur->random->next)
while(pcur)
{
Node* copy = pcur->next;
if(pcur->random == NULL)
copy->random = NULL;
else
copy->random = pcur->random->next;
pcur = pcur->next->next;
}
pcur = head;
Node* newhead = NULL, * newtail = NULL;
//将对应节点放到新链表中
while(pcur)
{
Node* next = pcur->next;
pcur->next = next->next;
if(newtail == NULL)
newhead = newtail = next;
else
{
newtail->next = next;
newtail = newtail->next;
}
pcur = pcur->next;
}
return newhead;
}