[LeetCode] 138. Copy List with Random Pointer

时间:2021-07-21 00:10:14

1. 原题链接:https://leetcode.com/problems/copy-list-with-random-pointer/

2. 解题思路

2.1 映射表
  1. 建立新旧节点之间的映射表:old->new,来解决复制random指针
2.2 克隆链表
  1. 创建一个包含新节点的克隆链表:A --> A‘ --> B --> B‘ --> C --> C‘ --> D --> D‘
  2. 关键点:A‘的random指针等于A的random指针指向的节点的next节点

3. 算法

3.1 映射表
  1. 建立新旧节点之间的映射表:old->new
  2. 遍历链表两次:
    1. 第一次遍历:构造新链表,只是对新链表的next指针进行赋值,同时建立旧节点和新建节点之间的映射表,此时不对random指针进行赋值
    2. 第二次遍历:根据映射表的映射关系,对新链表的random指针进行赋值
3.2 克隆链表
  1. 第一步:遍历原始链表:A --> B --> C --> D,创建一个包含新节点的克隆链表:A --> A‘ --> B --> B‘ --> C --> C‘ --> D --> D‘,注意此时不对random指针进行赋值
  2. 第二步:遍历新链表,当遍历到原始链表节点时,对该节点的下一个节点(也就是A和A‘的关系)的random指针进行赋值,该random指针指向原始节点的random指针指向的下一个节点
  3. 第三步:遍历新链表,把新节点从新链表中挑选出来,构成最终的copy链表并返回

4. 实现

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};
映射表
class Solution {
public:
    Node* copyRandomList(Node* head) {
        //建立新旧节点之间的映射表:old->new
        map<Node*, Node*> table;
        //第一次遍历:构造新链表,此时不对random指针进行赋值
        Node dummy(-1);
        Node *cur = head;
        Node *new_cur = &dummy;
        for(; cur != NULL; cur = cur->next, new_cur = new_cur->next){
            int v = cur->val;
            Node *new_node = new Node(v);
            table[cur] = new_node; //关键点:建立旧节点指针到新节点指针的映射
            new_cur->next = new_node;
        }
        
        //第二次遍历:对新链表的random指针进行赋值
        cur = head;
        new_cur = dummy.next;
        for(; cur != NULL; cur = cur->next, new_cur = new_cur->next){
            Node *r = cur->random;
            Node *new_r = table[r];
            new_cur->random = new_r;
        }
        return dummy.next;
    }
};
克隆链表
class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(!head)   return head;
        //copy new node and changing new node next pointer to old node next pointer and  old node next pointer to new node
        Node *newHead = NULL, *l1, *l2;
        for(l1 = head; l1 != NULL; l1 = l1->next->next){
            l2 = new Node(l1->val, l1->next, NULL);
            l1->next = l2;
        }
        newHead = head->next;
        //fixing the random pointer of the cloned list
        for(l1= head; l1 != NULL; l1 = l1->next->next){
            if(l1->random) l1->next->random = l1->random->next;
        }
        //changing the next node of both old and new list
        for(l1 = head; l1 != NULL; l1 = l1->next){
            l2 = l1->next;
            l1->next = l2->next;
            if(l2->next)l2->next = l2->next->next;
        }
        return newHead;
    }
};