【Leetcode C++】2_7. [code] 复制带随机指针的链表

7. [code] 复制带随机指针的链表

7.1 题目

Leetcode 138

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

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

示例:
Alt

输入:
{“KaTeX parse error: Expected '}', got 'EOF' at end of input: …":"1","next":{"id”:“2”,“next”:null,“random”:{“KaTeX parse error: Expected 'EOF', got '}' at position 9: ref":"2"}̲,"val":2},"rand…ref”:“2”},“val”:1}

解释:
节点 1 的值是 1,它的下一个指针和随机指针都指向节点 2 。
节点 2 的值是 2,它的下一个指针指向 null,随机指针指向它自己。

提示:

你必须返回给定头的拷贝作为对克隆列表的引用。

难度:中等

7.2. 思路

假定上述的带随机指针的链表的类型称为Node类。

定义如下,包含值val,指向下一节点的指针next,和随机指针random.

/*
// Definition for a Node.
class Node {
public:
    int val;
    Node* next;
    Node* random;

    Node() {}

    Node(int _val, Node* _next, Node* _random) {
        val = _val;
        next = _next;
        random = _random;
    }
};
*/

需要2个map,一个储存原Node链表的每个节点的地址和序号,另一个存储新Node链表的每个节点的地址和序号;由于新Node链表是原链表的拷贝,这里的序号的相同的,因此,第二的map可以用vector代替。

先创建一个新Node链表,则可以将这一新链表的每个节点的地址push入上述的vector,即这一vector储存了新Node链表的每个节点地址;

再遍历原Node链表,将原Node链表的每个节点的地址和序号分别储存入map的KEY和VALUE;

对新的Node链表需要两个操作:

  1. 每个节点next指针相连;
  2. 每个节点,如果存在ranndom,则random的指向;

7.3. 代码

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if (!head) return NULL;
        //定义<Node*, int>类型的map和<Node*>类型的vector
        std::map<Node*, int> node_map;
        std::vector<Node*> node_vec;
        //新链表的每个节点的地址push入上述的vector
        Node* ptr = head;
        int i=0;
        while(ptr){
            //vector存入新Node链表的地址
            node_vec.push_back(new Node(ptr->val)); 
            //map存入原Node链表的地址和序号
            node_map[ptr]=i;
            //下一个节点
            ptr = ptr->next;
            i++;
        }
        //将0加入node_vec的最末,确保后续node_vec最后一个节点的next指针指向不出错
        node_vec.push_back(0);
        //遍历原Node链表,
        ptr = head;
        i=0;
        while(ptr){
            //每个节点next指针相连
            node_vec[i]->next = node_vec[i+1];
            //每个节点,如果存在ranndom,则random的指向
            if (ptr->random){
                int id = node_map[ptr->random]; //该节点random指向的节点的序号
                node_vec[i]->random = node_vec[id];
            }
            ptr = ptr->next;
            i++;
        }
        return node_vec[0];
    }
};

提交到oj上有错误

下面这个方法简直神仙方法,太棒了:
先写一下代码

class Solution{
public:
    Node* copyRandomList(Node* head){
        if (!head) return nullptr;
        /* 将拷贝的节点接在原节点后面,再继续接下一个原节点 */
        for (Node* cur = head; cur != nullptr; ){
            Node* node = new Node(cur->val);
            node->next = cur->next;
            cur->next = node;
            cur = node->next;
        }
        /* 确定每个新节点的random指向 */
        for (Node* cur = head; cur != nullptr;) {
            if (cur->random != NULL){
                cur->next->random = cur->random->next;
            }
            else{
                cur->next->random = NULL;
            }
            cur = cur->next->next;  
        }

        /* 分离两个链表 */
        Node dummy(-1);
        Node* new_node = &dummy;
        for (Node* cur = head; cur != nullptr; ){
            new_node->next = cur->next;
            if(cur->next != NULL){
                cur->next = cur->next->next;
            }
            else{
                cur->next = NULL;
            }
            new_node = new_node->next;
            cur = cur->next;
        }

        return dummy.next;
    }
    
};
class Solution { 
public:
RandomListNode *copyRandomList(RandomListNode *head) { 
    for (RandomListNode* cur = head; cur != nullptr; ) { 
        RandomListNode* node = new RandomListNode(cur->label); 
        node->next = cur->next; 
        cur->next = node; 
        cur = node->next;
    }
    for (RandomListNode* cur = head; cur != nullptr; ) { 
        if (cur->random != NULL) 
            cur->next->random = cur->random->next;
        cur = cur->next->next; 
    }

    RandomListNode dummy(-1); 
    for (RandomListNode* cur = head, *new_cur = &dummy; cur != nullptr; ) {
        new_cur->next = cur->next; 
        new_cur = new_cur->next; 
        cur->next = cur->next->next; 
        cur = cur->next;
    } 
    return dummy.next; 
    } 
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值