题目描述
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
解题思路:
直接链表的复制是十分简单的,只需要一遍遍历就好了,O(n)复杂度。难度在于随机的的指针怎么值,如果按位次索引,即:从第1个节点Node1有一个随机指针指到Node2,然后我们从原链表头开始遍历,找到这个Node2,发现是第3个节点。那么在新链表中建立一个从第1个节点指到第3个节点的指针。这样的复杂度为n*O(n)是 O(n2)。
所以方案一:
建立原链表节点和新链表节点之间的哈希索引,额外空间O(n),时间效率O(n)
class Solution {
public:
/*unordered_map<RandomListNode*,RandomListNode*> mListMap; //建立哈希索引
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead==NULL)
return NULL;
RandomListNode* pRes = LineClone(pHead);
RandomListNode* pNode1 = pHead,*pNode2 = pRes;
while(pNode1!=NULL)
{
if(pNode1->random!=NULL) //再线性遍历一遍,完成随机指针的复制
pNode2->random = mListMap[pNode1->random]; //利用哈希表快速完成随机指针的复制
pNode1 = pNode1->next;
pNode2 = pNode2->next;
}
return pRes;
}
RandomListNode* LineClone(RandomListNode* pNode) //先进行线性复制
{
if(pNode==NULL)
return NULL;
RandomListNode* pNew = new RandomListNode(pNode->label);
pNew->next = LineClone(pNode->next);
mListMap[pNode] = pNew; //线性复制的同时建立哈希索引
return pNew;
}
};
方案二:
分三步:1、线性复制,每个新节点排列在原节点后面。
2、复制随机指针
3、原链表分裂非两个链表
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(pHead==NULL)
return NULL;
LineClone(pHead);
RandomClone(pHead);
return SplitList(pHead);
}
void LineClone(RandomListNode* pHead)
{
RandomListNode* pNode = pHead;
while(pNode)
{
RandomListNode* pNew = new RandomListNode(pNode->label);
pNew->next = pNode->next;
pNode->next = pNew;
pNode = pNew->next;
}
}
void RandomClone(RandomListNode* pHead)
{
auto pNode = pHead;
while(pNode)
{
if(pNode->random)
pNode->next->random = pNode->random->next;
pNode = pNode->next->next;
}
}
RandomListNode* SplitList(RandomListNode* pHead)
{
RandomListNode* pRes = pHead->next;
RandomListNode* pNode = pHead;
while(pNode->next)
{
auto pTmp = pNode->next; //注意不能破坏原来链表的结构
pNode->next = pTmp->next;
pNode = pTmp;
}
return pRes;
}
};