链接
https://leetcode.com/problems/copy-list-with-random-pointer/#/description
题意
一个链表,有三个属性:int lable
, RandomListNode* next
, RandomListNode* random
,其中random
可能指向该链表中的任意一个节点或者空结点,要求复制该链表
思路
我们用L表示原来的链表,L1表示复制后的链表
用x代表L中的节点,x’代表L1中的节点
思路1
最容易想到的思路就是先将链表的next
复制完后,再去复制random
。但是比如如下情况:
此时L的1的random
指向n,当L1复制random
指针的时候,如果需要定位到其的n’节点,需要
O(n)
的时间,那么时间复杂度最坏会上升到:
O(n2)
。
思路2
为了优化时间复杂度,我们需要做的就是:对于L1,如何快速定位到某个节点的random
指针指向的节点?
如上图:我们知道1->random = n
,那么需要得到1'->random = n'
。我们可以建立一个n
到n'
的映射,即用unorder_map<RandomListNode, RandomListNode>
来建立L到L1的节点的一一对应。
如下图所示:
这样,时间复杂度为
O(n)
,空间复杂度为
O(n)
思路3
空间复杂度能否继续优化?
既然我们不能用unordered_map
,观察上面的图:我们的unordered_map
就是为了建立映射,如1映射到1’,为什么不能直接用1指向1’呢?我们这样来建立链表:
这样,我们获得1’的random
指针时,只需要通过:1->next->random = 1->random->next
。
最后再将两个链表拆开即可。
细节
注意random
指向NULL
节点
代码
思路3的代码
/**
* Definition for singly-linked list with a random pointer.
* struct RandomListNode {
* int label;
* RandomListNode *next, *random;
* RandomListNode(int x) : label(x), next(NULL), random(NULL) {}
* };
*/
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
if (!head) return NULL;
RandomListNode* p = head;
while (p) {
RandomListNode* next_node = p->next;
p->next = new RandomListNode(p->label);
p->next->next = next_node;
p = next_node;
}
p = head;
while (p) {
p->next->random = p->random ? p->random->next : NULL;
p = p->next->next;
}
RandomListNode *cphead = head->next;
p = head;
while (p) {
RandomListNode* q = p->next;
p->next = p->next->next;
q->next = q->next ? q->next->next : NULL;
p = p->next;
}
return cphead;
}
};