题目
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
蠢人方法(我)
- 用链表A表示这个复杂链表。
- 第一步,先把链表A的主体部分复制出来,即先不管random指针。用B表示这个复制出来的链表。
- 第二步,对于链表B上的每一个节点nodeB,在链表A上有一个对应的nodeA, 遍历链表A找到nodeA->random的位置。让nodeB->random指向B链表对应位置的节点。
- 复杂度是 O ( n 2 ) O(n^2) O(n2)。
蠢人代码
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
RandomListNode* dummyHead = new RandomListNode(0);
// 复制主链
RandomListNode* pDummy = dummyHead;
RandomListNode* p = pHead;
while ( p ) {
RandomListNode* node = new RandomListNode( p->label );
pDummy->next = node;
p = p->next;
pDummy = pDummy->next;
}
// 确定每个节点的random
RandomListNode* p1 = pHead;
RandomListNode* pDummy1 = dummyHead->next;
while ( p1 ) {
RandomListNode* p2 = pHead;
RandomListNode* pDummy2 = dummyHead->next;
if ( p1->random == nullptr ) {
pDummy1->random = nullptr;
}
else {
while ( p1->random != p2 ) {
p2 = p2->next;
pDummy2 = pDummy2->next;
}
pDummy1->random = pDummy2;
}
p1 = p1->next;
pDummy1 = pDummy1->next;
}
return dummyHead->next;
}
};
用哈希表优化
- 上一个时间主要花费在了确定每个节点的random部分。
- 假设链表结点为 N N N, N N N-> r a n d o m random random为 S S S, N N N对应的复制节点为 N ′ N' N′, N ′ N' N′-> r a n d o m random random为 S ′ S' S′。
- 在第一步复制各节点的时候,用哈希表HT保存 < N , N ′ > <N,N'> <N,N′>。
- 在第二步确定random:
- 遍历原始链表,有 H T [ N ] = N ′ HT[N]=N' HT[N]=N′, H T [ S ] = S ′ HT[S]=S' HT[S]=S′。
- 所以有 H T [ N → r a n d o m ] = H [ S ] = S ′ HT[N \rightarrow random] = H[S]=S' HT[N→random]=H[S]=S′
- 所以 H [ N ] → r a n d o m = H [ N → r a n d o m ] H[N]\rightarrow random=H[N\rightarrow random] H[N]→random=H[N→random]
- 即 N ′ → r a n d o m = S ′ N'\rightarrow random = S' N′→random=S′
- 时间和空间复杂度都为O(N)。
代码
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
unordered_map<RandomListNode*, RandomListNode*> hashTable;
RandomListNode* dummyHead = new RandomListNode(0);
RandomListNode* p = pHead;
RandomListNode* pDummy = dummyHead;
// 复制原始链表上的每个节点。
while ( p ){
RandomListNode* node = new RandomListNode( p->label );
hashTable[p] = node;
pDummy->next = node;
p = p->next;
pDummy = pDummy->next;
}
// 确定每个节点的random
p = pHead;
while ( p ) {
/* 假如原节点为N,复制后的节点为N',N的random指向S,N'的random指向S'.
hashTable[N] = N',
hashTable[N->random] = hashTable[S] = S'*/
hashTable[p]->random = hashTable[p->random];
p = p->next;
}
return dummyHead->next;
}
};
O(n) 时间,O(1)空间
- 剑指offer188页
- 复制节点 N N N的时候,把 N ′ N' N′插入到N的后面。
- 遍历一遍链表,则N’->random = N->random->next。
- 把复制的节点和原节点分开。
代码
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
cloneNode( pHead );
setRandom( pHead );
return splitList( pHead );
}
void cloneNode( RandomListNode* p ) {
while( p ) {
RandomListNode* node = new RandomListNode( p->label );
node->next = p->next;
p->next = node;
p = node->next;
}
return;
}
void setRandom( RandomListNode* p ) {
RandomListNode* pNode = p;
RandomListNode* pClone = nullptr;
while ( pNode ) {
pClone = pNode->next;
if ( pNode->random != nullptr )
pClone->random = pNode->random->next;
pNode = pClone->next;
}
return;
}
RandomListNode* splitList( RandomListNode* p ) {
RandomListNode* dummyHead = new RandomListNode(0);
RandomListNode* pDummy = dummyHead;
while ( p ) {
pDummy->next = p->next;
p->next = p->next->next;
p = p->next;
pDummy = pDummy->next;
}
return dummyHead->next;
}
};