题目描述
请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。
https://leetcode.cn/problems/fu-za-lian-biao-de-fu-zhi-lcof/
题解
递归 + 哈希
对于递归,我们不需要知道整个问题要怎么解决,我们只需要关注当前节点的复制问题,还有递归的结束条件。
特别的,这道题我们使用记忆化递归的操作来避免重复复制节点,避免陷入递归循环。
但是实际上,执行顺序是先按照 ->next 顺序复制了所有节点(递),然后再回溯根据 copyRandomList(head->next)
的返回结果建立了 ->next 的关系(归);
另外 ->random 关系也在回溯时建立,所有的 copyRandomList(head->random)
调用都会直接返回 cache[head]
,因为所有节点都已经复制并存入了 cache 。
所以其实 copy->random = cache[head->random];
也是完全没有问题的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Solution { unordered_map<Node*, Node*> cache; public: Node* copyRandomList(Node* head) { if (!head) return nullptr; if (!cache.count(head)) { Node* copy = new Node(head->val); cache[head] = copy; copy->next = copyRandomList(head->next); copy->random = copyRandomList(head->random); } return cache[head]; } };
|
时间复杂度 O(N),空间复杂度 O(N)
迭代 + 哈希
先复制一个只有 next 指针的普通链表,并建立原链表和复制链表之间节点与节点的对应关系;
random 指针就是链表中的一个节点指向另一个节点,有了对应关系,再遍历原链表,实现 random 指针。
例:A -> B,根据对应关系,我们可以得到 A’ 和 B’,令 A’ -> B’ 即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public: Node* copyRandomList(Node* head) { unordered_map<Node*, Node*> oldToNew; Node* dummyHead = new Node(-1); Node* p = dummyHead; Node* cur = head; while (cur) { p->next = new Node(cur->val); p = p->next; oldToNew[cur] = p; cur = cur->next; } cur = head; while (cur) { oldToNew[cur]->random = cur->random ? oldToNew[cur->random] : nullptr; cur = cur->next; } return dummyHead->next; } };
|
时间复杂度 O(N),空间复杂度 O(N)
迭代 空间优化
对迭代方法进行空间优化,哈希的目的在于保存一种对应关系,我们可以利用原链表直接实现对应关系,不用哈希。
思路是在原链表节点的后面插入复制节点,将所有节点复制完成;
然后根据复制节点在原链表节点后面的关系,来代替哈希,并建立 random 指针的关系;
最后再实现 next 指针的指向,将复制的节点连成链表。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Solution { public: Node* copyRandomList(Node* head) { if (!head) return nullptr; for (Node* node = head; node != nullptr; node = node->next->next) { Node* copyNode = new Node(node->val); copyNode->next = node->next; node->next = copyNode; } for (Node* node = head; node != nullptr; node = node->next->next) { node->next->random = node->random ? node->random->next : nullptr; } Node* newHead = head->next; for (Node* node = head; node != nullptr; node = node->next) { Node* oldNext = node->next->next; node->next->next = oldNext ? oldNext->next : nullptr; node->next = oldNext; } return newHead; } };
|
时间复杂度 O(N),空间复杂度 O(1)