leetcode-138


LeetCode 138. 复制带随机指针的链表

1 题目描述

给你一个长度为 n 的链表,每个节点包含一个额外增加的随机指针 random ,该指针可以指向链表中的任何节点或空节点。

构造这个链表的 深拷贝。 深拷贝应该正好由 n全新 节点组成,其中每个新节点的值都设为其对应的原节点的值。新节点的 next 指针和 random 指针也都应指向复制链表中的新节点,并使原链表和复制链表中的这些指针能够表示相同的链表状态。复制链表中的指针都不应指向原链表中的节点

例如,如果原链表中有 XY 两个节点,其中 X.random --> Y 。那么在复制链表中对应的两个节点 xy ,同样有 x.random --> y

返回复制链表的头节点。

用一个由 n 个节点组成的链表来表示输入/输出中的链表。每个节点用一个 [val, random_index] 表示:

  • val:一个表示 Node.val 的整数。
  • random_index:随机指针指向的节点索引(范围从 0n-1);如果不指向任何节点,则为 null

你的代码 接受原链表的头节点 head 作为传入参数。

示例1:

输入: head = [[7,null],[13,0],[11,4],[10,2],[1,0]]
输出: [[7,null],[13,0],[11,4],[10,2],[1,0]]

示例2:

输入: head = [[1,1],[2,1]]
输出: [[1,1],[2,1]]

示例3:

输入: head = [[3,null],[3,0],[3,null]]
输出: [[3,null],[3,0],[3,null]]

2 思路

  • 迭代+链表拆分
    1. 遍历原链表,复制每一个节点,并将新节点连在原节点之后,即 node->next = new_node.
    2. 重新遍历链表,并根据原链表的 random 指向修改复制节点的 random 指针。具体的实现方法是: node->next->random = node->random->next .这里 node 指原链表的节点,node->next 为复制节点,node->random 指向原链表的节点的 random 节点,而对应的,node->random->next 则为复制节点 node->nextrandom 节点。
    3. 遍历整个链表,将当前遍历的节点的 next 节点存储下来,然后将当前节点的 next 指向下下个节点,从而实现两个链表的拆分。
/*
// 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) {
        if(!head) return head;

        Node *cur = head;
        while(cur){
            Node *node = new Node(cur->val);//将所复制的节点连在原链表对应节点的后边
            node->next = cur->next;
            cur->next = node;
            cur = cur->next->next;
        }
        cur = head;
        while(cur){                         //按照原链表的random指针修改复制链表的random指向
            if(cur->random){
                cur->next->random = cur->random->next;
            }else{
                cur->next->random = nullptr;
            }
            cur = cur->next->next;
        }
        Node *newHead = head->next;
        cur = head;
        while(cur && cur->next){
            Node *next = cur->next;         //拆分链表并还原两个链表
            cur->next = next->next;
            cur = next;
        }
        return newHead;
    }
};
  • 回溯+哈希
    1. 创建一个 KeyNode 节点,valNode 节点的 map.
    2. 遍历链表,复制当前节点并将当前节点作为 key, 而新节点作为 val 插入 map 中.
    3. 复制完链表后,遍历链表,按照 map 中的关系,将复制原链表的 random 指向。
class Solution {
public:
    map<Node*, Node*> m;
    Node* copyRandomList(Node* head) {
        if(!head) return nullptr;
        
        if(m.count(head)){
            return m[head];
        }
        Node *addNode = new Node(head->val);
        m[head] = addNode;
        addNode->next = copyRandomList(head->next);
        addNode->random = copyRandomList(head->random);   
        return addNode;
    }

文章作者: Vyron Su
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Vyron Su !