LeetCode-链表复制带随机指针的链表

Posted Flix

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode-链表复制带随机指针的链表相关的知识,希望对你有一定的参考价值。

题目描述

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

要求返回这个链表的 深拷贝。

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

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

示例:

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

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

思路1

分 3 步:
第 1 步,复制链表中的每个节点并放在该节点的后面

我们发现:

  • 原节点 1 的随机指针指向原节点 3,新节点 1 的随机指针指向的是原节点 3 的next;
  • 原节点 3 的随机指针指向原节点 2,新节点 3 的随机指针指向的是原节点 2 的next;

也就是也就是,原节点 i 的随机指针(如果有的话),指向的是原节点 j,那么新节点 i 的随机指针,指向的是原节点 j 的 next;
所以,第 2 步就是遍历链表,假设当前结点为 cur,则 cur->next->random = cur->random->next(如果 cur->random!=nullptr);

第 3 步就是把 2 个链表分开

这一步就是奇偶链表的做法。

/*
// 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==nullptr) return head;

        /*第1步:将复制的节点放在当前节点后面*/
        Node* cur = head;
        while(cur!=nullptr){
            Node* copy = new Node(cur->val);
            copy->next = cur->next;
            cur->next = copy;
            cur = cur->next->next;
        }

        /*第2步:设置复制的节点的random指针*/
        cur = head;
        while(cur!=nullptr){
            if(cur->random!=nullptr) cur->next->random = cur->random->next;  // 注意条件
            cur = cur->next->next;
        }

        /*第3步:分类两个链表*/
        Node* dummy = new Node(0);
        Node* cur1 = head;
        Node* cur2 = dummy;
        while(cur1 && cur2){
            Node* next1 = cur1->next;
            cur2->next = next1;
            cur1->next = next1->next;
            cur1 = cur1->next;
            cur2 = cur2->next;
        }
        return dummy->next;
    }
};

或者这样写,也是 3 个步骤,第 3 步的实现有点不同:

/*
// 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==NULL) return head;

        Node* cur = head;
        while(cur!=NULL){
            Node* copy = new Node(cur->val);
            Node* next = cur->next;
            cur->next = copy;
            copy->next = next;
            cur = next;
        } 

        cur = head;
        while(cur!=NULL){
            if(cur->random) cur->next->random = cur->random->next;
            cur = cur->next->next;
        }

        Node* dummy = new Node(0);
        cur = head;
        Node* newCur = dummy;
        while(cur!=NULL){
            newCur->next = cur->next;
            newCur = newCur->next;
            cur->next = cur->next->next;
            cur = cur->next;
        }
        return dummy->next;
    }
};

思路2

使用哈希表来做,哈希表为 unordered_map<Node*, Node*> hash,hash[node] = copy,也就是节点 node 对应它的拷贝 copy

因为节点和其拷贝是一一对应的,我们发现:

  • hash[cur]->next 就是 hash[cur->next];
  • hash[cur]->random 就是 hash[cur->random];

所以,我们先建立哈希表,然后遍历设置 next 和 random。

代码如下:

/*
// 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==nullptr) return head;

        unordered_map<Node*, Node*> hash;
        Node* cur = head;
        while(cur!=nullptr){
            Node* copy = new Node(cur->val);
            hash[cur] = copy;
            cur = cur->next;
        }

        cur = head;
        Node* newHead = hash[cur];
        while(cur!=nullptr){
            if(cur->next!=nullptr){
                hash[cur]->next = hash[cur->next];
            }
            if(cur->random!=nullptr){
                hash[cur]->random = hash[cur->random];
            }
            cur = cur->next;
        }
        return newHead;
    }
};

或者这样写(和上面的代码基本一样,做了一点简化):

/*
// 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==NULL) return head;

        unordered_map<Node*, Node*> hash;
        Node* cur = head;
        while(cur!=NULL){
            hash[cur] = new Node(cur->val);
            cur = cur->next;
        }

        cur = head;
        while(cur!=NULL){
            if(cur->next) hash[cur]->next = hash[cur->next];
            if(cur->random) hash[cur]->random = hash[cur->random];
            cur = cur->next;
        }
        return hash[head];
    }
};

参考

https://leetcode-cn.com/problems/copy-list-with-random-pointer/solution/liang-chong-shi-xian-tu-jie-138-fu-zhi-dai-sui-ji-/

以上是关于LeetCode-链表复制带随机指针的链表的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode-链表复制带随机指针的链表

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

LeetCode 138. 复制带随机指针的链表c++/java详细题解

Leetcode No.138 复制带随机指针的链表(回溯)

Leetcode No.138 复制带随机指针的链表(回溯)

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