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 作为传入参数。
题解
解法一:暴力求解(不推荐)
这个方法是我在解题时首先想到的,思路是先复制出一个有着同样链接关系的新链表newhead。
然后通过遍历数组得到每个结点random指向结点的相对位置
newhead的每个结点应该都指向相应的相对位置,例如第一个结点应该指向自己的第五个结点NULL
这样我们就找到了每一次的步长cnt,然后利用相对位置我们就能找出newhead链表的random指向。
最后上代码:
struct Node* ListBuyNode(int x)
{
struct Node *newnode = (struct Node*)malloc(sizeof(struct Node));
if (newnode == NULL)
{
perror("malloc error");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
newnode->random = NULL;
return newnode;
}
struct Node* copyRandomList(struct Node* head) {
struct Node* cur = head;
struct Node* newhead = NULL, *newcur = NULL;
while(cur)
{
struct Node* newnode = ListBuyNode(cur->val);
if(newhead == NULL)
{
newhead = newcur = newnode;
}
else
{
newcur->next = newnode;
newcur = newcur->next;
}
cur = cur->next;
}
cur = head;
newcur = newhead;
while(cur)
{
int cnt = 0;
struct Node* tail = head;
struct Node* newtail = newhead;
while(tail != cur->random) //计步长,即相对位置
{
cnt++;
tail = tail->next;
}
while(cnt--) //利用相对位置计算random
{
newtail = newtail->next;
}
newcur->random = newtail;
newcur = newcur->next;
cur = cur->next;
}
return newhead;
}
复杂度分析:时间复杂度O(N^2), 空间复杂度O(1)。
显然暴力求解的时间复制度并不理想,那么有更优的解法吗?
解法二:插入结点求解
此解法需要三步循环求解:
第一步:将原链表每个结点直接都插入一个相同值的新结点
此时我们即能观察发现:新结点copy->random = cur->random->next
第二步:将每个新结点的random都赋值为其前一个结点random的next
第三步:将复制出来的新节点与原链表脱离,构成一个新链表
最后上代码:
struct Node* copyRandomList(struct Node* head) {
struct Node* copy = NULL;
struct Node* cur = head;
struct Node* newhead = NULL, *tail = NULL;
while(cur)
{
struct Node* next = cur->next;
copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
cur->next = copy;
copy->next = next;
cur = next;
}
cur = head;
while(cur)
{
copy = cur->next;
if(cur->random)
copy->random = cur->random->next;
else
copy->random = NULL;
cur = copy->next;
}
cur = head;
while(cur)
{
copy = cur->next;
struct Node* next = copy->next;
if(newhead == NULL)
{
newhead = tail = copy;
}
else
{
tail->next = copy;
tail = tail->next;
}
cur->next = next;
cur = next;
}
return newhead;
}
复杂度分析:时间复杂度O(N),空间复杂度O(1)