Description:
A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.
Return a deep copy of the list.
加上了一个随机指针的链表,随机指针会随机地指向链表中的任意一个节点或者NULL,要求实现深拷贝。
Solution:
一开始理解错题意了,以为random指针还是直接指向原来的地址即可,后面细细一想,发现并没有那么简单。
这题也出现在《剑指offer》这本书上,看了解法之后越来越觉得这是一个好题,经典题,此题有三种解法,从坏到好一一细说:
Ⅰ超级暴力法。
1、其实难点就是在于我们不知道random指针指向的是哪个节点,既然不知道,那么我们就逐一遍历找到它指向的是第几个节点;
2、在深拷贝时,我们先实现好基本不包括random指针的链表;
3、之后在对原链表进行遍历找出每个的random指针指向的是第几个节点,然后找到新链表对应的下标节点,即可。
时间复杂度为O(n²),空间复杂度为O(1)
Ⅱ map实现(哈希表)
1、我们其实不需要random指向的是第几个节点,我们只需要建立好一个新节点与旧节点的一一对应关系即可;
2、建立好了之后,我们通过random指向的旧节点和map对应关系就能知道新节点的地方。
时间复杂度为O(n),空间复杂度为O(n)
Ⅲ O(1)空间复杂度实现
假如原链表表示为A(C)->B(A)->C(A)->NULL,括号里表示为随机指向的节点;
1、我们先将链表拷贝成如此:
A(C)->A’->B(A)->B’->C(A)->C’->NULL
即将旧链表的每一个节点的next指针指向新链表对应节点,换句话说,就是将新链表间隔地插入旧链表中。
2、拷贝random指针,执行了第一步之后,我们需要找random指针就好找许多,如下:
oldnode->next->random=oldnode->random->next
完成拷贝之后链表如下:
A(C)->A’(C’)->B(A)->B’(A’)->C(A)->C’(A’)->NULL
3、将新链表和旧链表分离即可,得到两个链表:
A(C)->B(A)->C(A)->NULL
A’(C’)->B’(A’)->C’(A’)->NULL
如此做的做法时间复杂度为O(n),空间复杂度为O(1)
Code:
Ⅱ:
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
map<RandomListNode*, RandomListNode*> newold;
RandomListNode* oldtemp = head;
if (head == NULL)
return head;
RandomListNode* pre = NULL;
RandomListNode* newhead = NULL;
while (head)
{
RandomListNode* cur = new RandomListNode(head->label);
newold[head] = cur;//build a relationship between new nodes and old nodes
if (pre)
pre->next = cur;
else
newhead = cur;
pre = cur;
head = head->next;
}
while (oldtemp)
{
newold[oldtemp]->random=newold[oldtemp->random];
oldtemp=oldtemp->next;
}
return newhead;
}
};
Ⅲ:
class Solution {
public:
RandomListNode *copyRandomList(RandomListNode *head) {
RandomListNode* temp=head;
if(!head)
return head;
while(temp)
{
RandomListNode* align=new RandomListNode(temp->label);
align->next=temp->next;
temp->next=align;
temp=align->next;
}//the first step
temp=head;
while(temp)
{
if(temp->random)
temp->next->random=temp->random->next;
temp=temp->next->next;
}//the second step
temp=head;
RandomListNode* ans=temp->next;
while(temp)
{
RandomListNode* al=temp->next;
temp->next=al->next;
temp=al->next;
if(al->next)
al->next=al->next->next;
}//split new link and old link
return ans;
}
};