复制带随机指针的链表
给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点。
要求返回这个链表的深度拷贝。
这里参考了博文:
https://www.cnblogs.com/TenosDoIt/p/3387000.html(图画的很赞,这里借用了)
https://blog.csdn.net/sun20082567/article/details/36198817(图画的也很赞)
这道题由于链表带随机指针,如果每次遍历都去找每个节点的random指针,那么时间复杂度为O(n),如下图所示:
黑色表示random指针,蓝色表示next指针,未标出表示random指针为nullptr
首先通过原链表构建1'->2'->3'->4',然后对节点1',应该把1'的指针指向3',但是我们怎么得到1'->3'的映射关系呢?我们只有1->3的映射关系,所以直观的想法便是通过计数器来保存每一个节点的random指针是第几个节点,通过next遍历得到,对每一个节点都需要遍历一次原链表,时间复杂度是O(n^2),肯定time limited。所以需要换种思想:
算法一:
由上述的提示,如果我们能找到原链表和新链表的映射关系,便可以直接构造新链表的random指针,所以我们需要一个map,
如下图所示:
map的映射关系为key:old_node,value:new_node,更新规则如下公式:
mapper[head_tmp] = new_head_tmp;
然后寻找random指针时用以下公式:
new_head_tmp->random = mapper[head_tmp->random];
代码如下,时间复杂度(O(n)),空间复杂度(O(n)):
RandomListNode *copyRandomList(RandomListNode *head) {
if (!head) {
return head;
}
RandomListNode *head_tmp = head;
RandomListNode *new_head = new RandomListNode(head->label);
RandomListNode *new_head_tmp = new_head;
head_tmp = head_tmp->next;
map<RandomListNode *, RandomListNode *> mapper;
mapper[head] = new_head;
while (head_tmp) {
RandomListNode *new_node = new RandomListNode(head_tmp->label);
new_head_tmp->next = new_node;
new_head_tmp = new_head_tmp->next;
mapper[head_tmp] = new_head_tmp;
head_tmp = head_tmp->next;
}
head_tmp = head;
new_head_tmp = new_head;
while (head_tmp) {
if (head_tmp->random) {
new_head_tmp->random = mapper[head_tmp->random];
}
head_tmp = head_tmp->next;
new_head_tmp = new_head_tmp->next;
}
return new_head;
}
算法2:
我们把空间复杂度降为O(1),具体如下图所示:
第一次遍历原链表时把新节点加到原链表每个节点后面,
第二次遍历更新新节点的random指针,公式为:
new_head_tmp->random = old_head_tmp->random->next;
第三次遍历把原链表和新链表分开
代码如下:
RandomListNode *copyRandomList(RandomListNode *head) {
if (!head) {
return head;
}
RandomListNode *old_head_tmp = head;
RandomListNode *new_head = new RandomListNode(head->label);
RandomListNode *new_head_tmp = new_head;
new_head->next = head->next;
head->next = new_head;
old_head_tmp = old_head_tmp->next->next;
while (old_head_tmp) {
RandomListNode *new_node = new RandomListNode(old_head_tmp->label);
new_node->next = old_head_tmp->next;
old_head_tmp->next = new_node;
old_head_tmp = old_head_tmp->next->next;
}
old_head_tmp = head;
new_head_tmp = head->next;
while (old_head_tmp) {
if (old_head_tmp->random) {
new_head_tmp->random = old_head_tmp->random->next;
}
old_head_tmp = old_head_tmp->next->next;
new_head_tmp = old_head_tmp!=nullptr?new_head_tmp->next->next:nullptr;
}
old_head_tmp = head;
new_head_tmp = head->next;
while (old_head_tmp) {
old_head_tmp->next = old_head_tmp->next->next;
new_head_tmp->next = old_head_tmp->next != nullptr ? new_head_tmp->next->next : nullptr;
old_head_tmp = old_head_tmp->next;
new_head_tmp = new_head_tmp->next;
}
return new_head;
}