[35]复杂链表的复制
1.题目
请实现一个函数可以复杂复杂链表
在复杂链表中,每一个节点除了有一个指针指向下一个节点,还有一个额外的指针指向链表中的任意节点或者null
图中实线箭头表示
next
指针,虚线箭头表示random
指针,为了简答起见指向nullptr
的指针没有画出
2.分析
- 函数结束后原链表要与输入时保持一致
3.思路
【1】.一般思路
- 复杂原链表中的每一个节点,并用
next
链接起来 - 设置每一个节点的
random
指针- 对于一个含有 n 个节点的链表,定位每一个
random
都需要从链表头节点开始经过 O ( n ) O(n) O(n)步才能找到,因此总的时间复杂度是 O ( n 2 ) O(n^2) O(n2)
- 对于一个含有 n 个节点的链表,定位每一个
【2】.利用哈希表用空间换时间
- 复制原链表上的每一个节点 N 创建 N’,并用
next
链接起来,同时我们把 <N,N’>的配对信息放到哈希表中; - 设置复制链表上的
random
。如果原始链表中节点 N 的random
指向 S ,那么复制链表中,对应的 N’ 应该指向 S’ 。- 由于有了 哈希表 ,我们可以用 O ( 1 ) O(1) O(1)的时间,根据 S 找到 S’。
- 我们以 O ( n ) O(n) O(n)的空间复制度把时间复制度由 O ( n 2 ) O(n^2) O(n2) 降到了 O ( n ) O(n) O(n)
【3】
-
复制原始链表中任意节点 N 并创建 N’ ,再把 N’ 链接到 N 的后面
-
设置复制出来的节点的
random
-
把这个长链表拆分为两个链表
- 奇数位置用next链接,就是原链表
- 偶数位置用next链接,就是复制出来的链表
思路动画
4.代码
/**
* Definition for singly-linked list with a random pointer.
* struct ListNode {
* int val;
* ListNode *next, *random;
* ListNode(int x) : val(x), next(NULL), random(NULL) {}
* };
*/
class Solution {
public:
ListNode *copyRandomList(ListNode *head) {
for(auto p = head; p;) // 复制链表
{
auto pCopy = new ListNode(p->val);
auto temp = p->next;
p->next = pCopy;
pCopy->next = temp;
p = temp; // 移动节点
}
for(auto p = head; p; p = p->next->next) // 设置复制出来节点的random
{
if(p->random)
p->next->random = p->random->next;
}
auto dummy = new ListNode(-1);
auto cur = dummy;
auto p = head;
while(p)
{
cur->next = p->next;
cur = cur->next; // cur 现在指向复制节点
p = cur->next; // 还原链表
}
return dummy->next;
}
};