剑指 Offer 35. 复杂链表的复制

法一

我们首先将该链表中每一个节点拆分为两个相连的节点,例如对于链表 \(A \rightarrow B \rightarrow C\),我们可以将其拆分为 \(A \rightarrow A' \rightarrow B \rightarrow B' \rightarrow C \rightarrow C'\)。对于任意一个原节点 S,其拷贝节点 S' 即为其后继节点。

这样,我们可以直接找到每一个拷贝节点 S' 的随机指针应当指向的节点,即为其原节点 S 的随机指针指向的节点 T 的后继节点 T' 。需要注意原节点的随机指针可能为空,我们需要特别判断这种情况。

当我们完成了拷贝节点的随机指针的赋值,我们只需要将这个链表按照原节点与拷贝节点的种类进行拆分即可,只需要遍历一次。同样需要注意最后一个拷贝节点的后继节点为空。

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {
        for (Node* p = head; p; p = p->next->next) {
            Node* node = new Node(p->val);
            node->next = p->next;
            p->next = node;
        }

        for (Node* p = head; p; p = p->next->next) {
            Node* node = p->next;
            if (p->random)
                node->random = p->random->next;
        }

        Node* newHead = new Node(-1);
        Node* cur = newHead;
        for (Node* p = head; p; p = p->next) {
            cur->next = p->next;
            cur = cur->next;
            p->next = p->next->next;
        }
        return newHead->next;
    }
};

法二

本题要求我们对一个特殊的链表进行深拷贝。如果是普通链表,我们可以直接按照遍历的顺序创建链表节点。而本题中因为随机指针的存在,当我们拷贝节点时,「当前节点的随机指针指向的节点」可能还没创建。

如果不考虑 random 指针的话,对一条链表进行拷贝,我们只需要使用两个指针:一个用于遍历原链表,一个用于构造新链表(始终指向新链表的尾部)即可。这一步操作可看做是「创建节点 + 构建 next 指针关系」。

现在在此基础上增加一个 random 指针,我们可以将 next 指针和 random 指针关系的构建拆开进行:

先不考虑 random 指针,和原本的链表复制一样,创建新节点,并构造 next 指针关系,同时使用「哈希表」记录原节点和新节点的映射关系;

对原链表和新链表进行同时遍历,对于原链表的每个节点上的 random 都通过「哈希表」找到对应的新 random 节点,并在新链表上构造 random 关系。

有了哈希表,我们可以用\(O(1)\)的时间根据 S 找到 S'。

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;
    
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};
*/
class Solution {
public:
    Node* copyRandomList(Node* head) {
        unordered_map<Node*, Node*> mp;

        Node* dummy = new Node(-1);
        Node* cur = dummy;
        for (Node* p = head; p; p = p->next) {
            Node* node = new Node(p->val);
            cur->next = node;
            cur = cur->next;
            mp[p] = node;
        }

        for (Node *p = head, *q = dummy->next; p; p = p->next, q = q->next) {
            q->random = mp[p->random];
        }

        return dummy->next;
    }
};
posted @ 2021-07-27 23:22  Dazzling!  阅读(37)  评论(0编辑  收藏  举报