解题思路
乍一看此题感觉不就是遍历链表,然后连接嘛,这样暴力解决的话肯定是可行的,但是我们不知道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; } };