解题思路
乍一看此题感觉不就是遍历链表,然后连接嘛,这样暴力解决的话肯定是可行的,但是我们不知道random出现在当前节点前面还是后面,导致不能一次遍历就能连接全部。
一种方法是保存节点与复制节点的成对的hash关系,根据`r = node->random`,去找对,就能快速找到node'对应的random节点。
不过,此种方式需要开辟O(N)大小的空间。
本题解采用另外一种方式,即大事化小策略,并且不用开辟额外空间。
把这个问题分解为三部分:
复制节点,并且直接连接在当前被复制节点的后面,也就是说原来的
head = [A, B, C]经过此操作后变为head = [A, A', B, B', C, C']给新复制的节点连接对应的
random拆分
head,返回copy,并且保持原head不变。
代码
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead) {
copyNodes(pHead);
connectRandom(pHead);
return reconnect(pHead);
}
private:
/**
* 复制每一个Node使之连接在当前被复制的Node后面。
* @example head = [A, B, C], 操作后 head = [A, A', B, B', C, C']
* @param head
*/
void copyNodes(RandomListNode* head) {
if (head == nullptr) return;
RandomListNode* pHead = head;
while (pHead != nullptr) {
RandomListNode* cloned = new RandomListNode(pHead->label);
cloned->next = pHead->next;
pHead->next = cloned;
pHead = cloned->next;
}
}
/**
* 连接random
* @example A'->random = B'
* @param head
*/
void connectRandom(RandomListNode* head) {
if (head == nullptr) return;
RandomListNode* pHead = head;
while (pHead != nullptr) {
RandomListNode* cloned = pHead->next;
if (pHead->random != nullptr)
cloned->random = pHead->random->next;
pHead = cloned->next;
}
}
/**
* 取head的偶数节点,重新连接为head',并且head恢复为[A, B, C]
* @example head = [A, A', B, B', C, C'] => head = [A, B, C], head' = [A', B', C']
* @param head
* @return head'
*/
RandomListNode* reconnect(RandomListNode* head) {
if (head == nullptr) return nullptr;
RandomListNode* pHead = head;
RandomListNode *copy = nullptr, *pNode = nullptr;
if (pHead != nullptr) {
copy = pNode = head->next; // copy = A'
pHead = copy->next; // pHead = B;
head->next = pHead; // head->next = B;
}
while (pHead != nullptr) {
pNode->next = pHead->next; // A' -> next = B'
pNode = pHead->next;
pHead->next = pNode->next; // B->next = C;
pHead = pHead->next;
}
return copy;
}
}; 
京公网安备 11010502036488号