本题主要考验代码能力
题目描述:
题号:138
给你一个长度为 n
的链表,每个节点包含一个额外增加的随机指针 random
,该指针可以指向链表中的任何节点或空节点。
构造这个链表的 深拷贝。 深拷贝应该正好由 n
个 全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next
指针和 random
指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点 。
例如,如果原链表中有 X
和 Y
两个节点,其中 X.random --> Y
。那么在复制链表中对应的两个节点 x
和 y
,同样有 x.random --> y
。
返回复制链表的头节点。
解题思路:
思路一:先原地复制,后拆分
-
原地复制节点:
-
遍历原链表,对于每个节点,将其
next
指针指向一个新创建的节点,该新节点的值与当前节点相同。 -
然后,将这个新节点的
next
指针指向原节点的下一个节点,从而在原链表中每个节点后面都插入了一个复制的新节点。
-
-
复制随机指针:
-
再次遍历修改后的链表,这次遍历时,对于每个原节点(我们可以通过跳过一个节点来访问它们),我们设置其后面复制节点(即新节点)的
random
指针。 -
如果原节点的
random
指针不为空,则新节点的random
指针指向原节点random
指针指向的节点的下一个节点(即random
指针对应节点的复制节点)。
-
-
拆分链表:
-
最后,我们需要将原链表和复制后的新链表分离开来。首先,我们记录下原链表头节点的下一个节点,这将是新链表的头节点。
-
然后,再次遍历链表,这次我们同时更新原链表和新链表的
next
指针,使它们各自独立成链。对于原链表,我们跳过每个复制节点来连接原节点;对于新链表,我们做类似的操作。
-
-
返回新链表头节点:
-
遍历完成后,我们就得到了两个独立的链表:原链表和复制后的新链表。我们返回之前记录下的新链表的头节点。
-
时间复杂度:O(N)
空间复杂度:O(1)
C++
// C++
/*
// Definition for a Node.
class Node {
public:
int val;
Node* next;
Node* random;
Node(int _val) {
val = _val;
next = NULL;
random = NULL;
}
};
*/
class Solution {
public:
Node* copyRandomList(Node* head) {
if(head == nullptr) {
return nullptr;
}
// 复制节点
Node *cur = head;
while(cur) {
Node *temp = cur->next;
cur->next = new Node(cur->val);
cur->next->next = temp;
cur = temp;
}
// 复制随机指针
cur = head;
while(cur) {
Node *temp = cur->next;
temp->random = cur->random == nullptr ? nullptr : cur->random->next;
cur = cur->next->next;
}
// 拆分
// A1->A2->B1->B2->C1->C2
Node *newHead = head->next;
cur = head;
Node *newCur = head->next;
while(cur) {
cur->next = cur->next->next;
cur = cur->next;
newCur->next = newCur->next == nullptr ? nullptr : newCur->next->next;
newCur = newCur->next;
}
return newHead;
}
};
go
// go
/**
* Definition for a Node.
* type Node struct {
* Val int
* Next *Node
* Random *Node
* }
*/
func copyRandomList(head *Node) *Node {
if head == nil {
return nil
}
// 复制节点
cur := head
for cur != nil {
next := cur.Next
cur.Next = &Node{Val: cur.Val}
cur.Next.Next = next
cur = next
}
// 复制随机指针
cur = head
for cur != nil {
curNew := cur.Next
if cur.Random != nil {
curNew.Random = cur.Random.Next
}
cur = cur.Next.Next
}
// 拆分
// A1->A2->B1->B2->C1->C2
newHead := head.Next
cur = head
curNew := head.Next
for cur != nil {
cur.Next = cur.Next.Next
cur = cur.Next
if curNew.Next != nil {
curNew.Next = curNew.Next.Next
}
curNew = curNew.Next
}
return newHead
}