输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点)
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
这里随机指针用random来命名,有些地方使用的是sibling来命名的。
通常的做法是用哈希表来做,显然,这样就要额外使用O(n)的空间复杂度。
取巧的做法是使用O(1)的额外空间复杂度,但需遍历3次链表。下面图形来说明一下。
如上图所示,为五个结点的复杂链表,实线表示next指针,虚线表示random指针。
整个算法分为三步:
1.clone原链表,得到如下形式的新链表。只复制next指针。此步中,忽略random指针。
2.此步处理random指针。
由于每个结点对应的clone结点就是其下一个,所以使用
if(nullptr != pNode->random)
pCloneNode->random = pNode->random->next;
就可以正确得到新链表的random值。
3.此步用于分离原链表和新链表。
综上所述,AC代码如下:
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
//不使用额外空间,在O(n)时间复杂度内
if(nullptr == pHead)
return nullptr;
RandomListNode* pCloneNode = nullptr, *pNode = pHead;
//stage1 clone in
while(nullptr != pNode)
{
pCloneNode = new RandomListNode(pNode->label);
pCloneNode->next = pNode->next;
pNode->next = pCloneNode;
pNode = pCloneNode->next;
}
//stage2 duplicate random ptr
pNode = pHead;
pCloneNode = pNode->next;
while(nullptr != pCloneNode->next)
{
if(nullptr != pNode->random)
pCloneNode->random = pNode->random->next;
pNode = pCloneNode->next;
pCloneNode = pNode->next;
}
//the last pair
if(nullptr != pNode->random)
pCloneNode->random = pNode->random->next;
//stage3 seperate the original link and the clone
pNode = pHead;
pCloneNode = pNode->next;
RandomListNode* pCloneHead = pCloneNode;
while(nullptr != pCloneNode->next)
{
pNode->next = pCloneNode->next;
pNode = pNode->next;
pCloneNode->next = pNode->next;
pCloneNode = pCloneNode->next;
}
pNode->next = nullptr;
pCloneNode->next = nullptr;
return pCloneHead;
}
};