138. Copy List with Random Pointer

目录

题目描述

方法一、使用哈希表

方法二、不使用哈希表


题目描述

问题的关键是,random指针指向的是原链表的结点,这个原链表的结点对应哪一个新链表的结点呢?有两种办法。一是用哈希表。另一种是复制原链表的每一个结点,并将新结点接在原结点的后面组成一个长度加倍的链表,这样原结点的直接后继就是该原结点对应的新结点。

方法一、使用哈希表

unordered_map<Node*,Node*> new_table;//键是原链表中的旧结点,值是新链表中的新结点

unordered_map<Node*,Node*> random_table;//键是原链表中的旧结点,值是该旧结点的random指针指向的结点

cpp 复制代码
/*
// 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 nullptr;
        unordered_map<Node*,Node*> new_table;//键是原链表中的旧结点,值是新链表中的新结点
        unordered_map<Node*,Node*> random_table;//键是原链表中的旧结点,值是该旧结点的random指针指向的结点
        Node* newHead = nullptr;
        Node* newTail = nullptr;
        Node* cur = head;

        //第一步,建立新链表
        while(cur){
            Node* node = new Node(cur->val);
            new_table.insert({cur,node});
            random_table.insert({cur,cur->random});
            if(newHead == nullptr){
                newHead = node;
                newTail = node;
            }else{
                newTail->next = node;
                newTail = node;
            }
            cur = cur->next;
        }

        //第二步,设置新链表结点的random指针
        for(const auto& [old_node,new_node] : new_table)
        {
            if(random_table[old_node]){
                new_node->random = new_table[random_table[old_node]];
            }
        }
        return newHead;
    }
};

实际上前面做法中的random_table是可以不需要的。

cpp 复制代码
/*
// 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 nullptr;
        unordered_map<Node*,Node*> new_table;//键是原链表中的旧结点,值是新链表中的新结点
        Node* newHead = nullptr;
        Node* newTail = nullptr;
        Node* cur = head;
        //第一步,建立新链表
        while(cur){
            Node* node = new Node(cur->val);
            new_table.insert({cur,node});
            if(newHead == nullptr){
                newHead = node;
                newTail = node;
            }else{
                newTail->next = node;
                newTail = node;
            }
            cur = cur->next;
        }

        cur = head;
        Node* new_cur = newHead;
        //第二步,设置新链表结点的random指针
        while(cur){
            if(cur->random){
                new_cur->random = new_table[cur->random];
            }
            cur = cur->next;
            new_cur = new_cur->next;
        }

        return newHead;
    }
};

方法二、不使用哈希表

第一步,复制每一个旧结点,并将新结点接在旧结点的后面组成新旧结点交替出现的长度翻倍的大链表。

第二步,设置新结点的random指针。

第三步,从大链表中提取出新结点组成新链表,并将原链表复原。

需要着重强调的是,第二步和第三步必须分开来做。

cpp 复制代码
/*
// 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 nullptr;
        Node* cur = head;
        //复制每一个旧结点,并将新结点接在旧结点的后面
        while(cur){
            Node* node = new Node(cur->val);
            Node* temp = cur->next;
            node->next = cur->next;
            cur->next = node;
            cur = temp;
        }

        cur = head;
        //设置新结点的random指针
        while(cur){
            if(cur->random)
                cur->next->random = cur->random->next;
            cur = cur->next->next;//原链表向前走一位
        }

        Node* new_head = nullptr;
        Node* new_tail = nullptr;
        cur = head;
        //提取出新结点组成新链表,并将原链表复原
        while(cur){
            if(new_head == nullptr){
                new_head = cur->next;
                new_tail = cur->next;
            }else{
                new_tail->next = cur->next;
                new_tail = cur->next;
            }
            cur->next = cur->next->next;//复原原链表
            cur = cur->next;//原链表向前走一步
        }

        return new_head;
    }
};
相关推荐
wuyk5556 小时前
3.链表:用指针串联的动态数据结构
c语言·开发语言·数据结构·链表
郝学胜-神的一滴6 小时前
干货版《算法导论》17:二叉树核心原理、遍历逻辑与高阶实操全解
数据结构·c++·python·算法·计算机·编程
疯狂打码的少年7 小时前
【数据结构】二叉树的性质(五大性质+计算)
数据结构·笔记·算法
wabs6668 小时前
关于图论【A*算法 | 卡码网127.骑士的攻击的思考】
数据结构·算法·图论·卡码网·广搜的改进版
凉茶钱8 小时前
【数据结构】堆的应用
c语言·数据结构
间歇性努力持续性发呆的野生快乐选手9 小时前
栈的性质(进栈,出栈,访问)
数据结构·c++
m0_547486669 小时前
《数据结构与算法》全套PPT课件2026(中国海洋大学)
数据结构·算法
旖旎夜光10 小时前
LeetCode 904:水果成篮(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
我变成萤火虫12 小时前
河南萌新联赛2026第(三)场:郑州轻工业大学
数据结构·c++·算法·贪心算法·stl·深度优先·哈希算法
白狐_79812 小时前
408数据结构第7章:B树①——基础概念与结构
数据结构·b树