剑指offer 复杂链表的复制(两种方法:哈希表、拼接再拆分)

题目:

请实现 copyRandomList 函数,复制一个复杂链表。在复杂链表中,每个节点除了有一个 next 指针指向下一个节点,还有一个 random 指针指向链表中的任意节点或者 null。

剑指offer 复杂链表的复制(两种方法:哈希表、拼接再拆分)_第1张图片

 方法一:利用哈希表建立原链表与新链表节点的映射关系

解题思路:

1.先构建 原链表节点 和 新链表对应节点 的映射关系

2.再遍历构建新链表各节点的 next 和 random 引用指向

源代码如下:

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head==nullptr) return nullptr;//链表为空时,直接返回空
        Node* cur =head;
        unordered_map map;//映射关系map(原节点,新节点)
        //先建立与原链表的映射关系
        while(cur)
        {
            //节点的值与原节点值相同
            map[cur]=new Node(cur->val);
            cur=cur->next;
        }
        //cur置为head头节点,重新遍历原链表
        cur=head;
        //建立新链表的next指针和random指针
        while(cur)
        {
            map[cur]->next=map[cur->next];
            map[cur]->random=map[cur->random];
            cur=cur->next;
        }
        //返回新的头节点,map[head]对应的就是新的头节点
        return map[head];
    }
};

时间复杂度:O(n)

空间复杂度: O(n)

我们可以继续优化一下,将空间复杂度优化至 O(1)

方法二:先拼接再拆分

解题思路:

1.构建拼接链表:使链表变为原链表节点1->新链表节点1->原链表节点2->新链表节点2->...

这样新链表各节点的next指向已基本完成

2.构建新链表各节点的random 引用指向

3.拆分原链表和新链表

源代码如下:

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head==nullptr) return nullptr;
        Node* cur =head;
        //先拼接,将原链表的每个节点后面拼接一个新的节点,顺序不改变
        while(cur)
        {
            Node* node=new Node(cur->val);
            node->next=cur->next;
            cur->next=node;
            cur=node->next;
        }
        //这样拼接完成后,新链表的next指针的指向已经完成了
        //将cur指针重置为头节点,遍历链表
        cur=head;
        //建立新链表的random指针的指向
        //原链表的节点是cur,那么新链表的节点就是cur->next
        //原链表中cur->random,在新链表中对应的就是cur->random->next
        //所以新链表的random指针的建立为cur->next->random=cur->random->next;
        while(cur)
        {
            if(cur->random!=nullptr)
                cur->next->random=cur->random->next;
            cur=cur->next->next;
        }
        //接下来进行原链表和新链表的拆分
        Node* pre=head;//原链表的指针
        cur=head->next;//新链表的指针
        Node* res=head->next;//新链表的头节点
        while(cur->next)
        {
            pre->next=pre->next->next;
            cur->next=cur->next->next;
            pre=pre->next;
            cur=cur->next;
        }
        //原链表的尾节点需单独置为nullptr
        pre->next=nullptr;
        //返回新链表的头节点
        return res;
    }
};

时间复杂度:O(n)

空间复杂度:  O(1)

你可能感兴趣的:(链表,散列表,数据结构,leetcode,c++)