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


    法一

    我们首先将该链表中每一个节点拆分为两个相连的节点,例如对于链表 (A ightarrow B ightarrow C),我们可以将其拆分为 (A ightarrow A' ightarrow B ightarrow B' ightarrow C ightarrow 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;
        }
    };
    
  • 相关阅读:
    计算机网络 其他1
    C++ part9
    C++ part8
    操作系统 part5
    C++ part7
    MyXls导出Excel的各种设置
    C# excel操作
    Castle
    C# Keycode对照表
    IEnumerable.Select和SelectMany的区别
  • 原文地址:https://www.cnblogs.com/fxh0707/p/15068416.html
Copyright © 2020-2023  润新知