Leetcode刷题笔记——剑指 Offer 35. 复杂链表的复制

本博客探讨了如何解决Leetcode上的剑指 Offer 35问题,即复杂链表的复制。难点在于随机指针可能导致在拷贝过程中目标节点未创建。采用的策略是在第一次遍历中为所有节点创建副本并插入原链表,然后遍历新链表,根据原链表的random指针更新新链表的random指针,最后断开新链表并连接成最终结果。此外,还介绍了使用HashMap来辅助拷贝节点的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

在这里插入图片描述

分析

本题要求我们对一个特殊的链表进行深拷贝。如果是普通链表,我们可以直接按照遍历的顺序创建链表节点。而本题中因为随机指针的存在,当我们拷贝节点时,「当前节点的随机指针指向的节点」可能还没创建,因此我们需要变换思路。一个可行方案是,我们利用回溯的方式,让每个节点的拷贝操作相互独立。对于当前节点,我们首先要进行拷贝,然后我们进行「当前节点的后继节点」和「当前节点的随机指针指向的节点」拷贝,拷贝完成后将创建的新节点的指针返回,即可完成当前节点的两指针的赋值。

即本题难点在于该随机指针在深拷贝时其内容尚未创建。

解决思路:官方解题思路有两个,其中学习第二种。对于本题难点,可以在第一遍遍历该链表的时候就new一遍所有的节点,保证在后续深拷贝时每一个random指针的对象都已经被创建。

具体的:
1、遍历链表,在每一个节点之后new一个节点,将new的节点插入原链表中,这样保证了只要原链表存在一个节点,这个节点之后必定有我们新new的节点。
2、遍历新链表,对原节点进行遍历,遍历时读取random指针指向的节点,将该节点后的new节点的random指针指向random->next,一遍遍历之后,所有新new的节点的random都会指向新new的节点。
3、遍历新链表,断链。恢复原链表,将新new的节点连接起来构成res。

代码

/*
// 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 nullptr;
        for(Node* p = head; p ; p = p->next->next){
            Node* newNode = new Node(p->val);
            if(p->next){
                newNode->next = p->next;
                p->next = newNode;
            }else{
                newNode->next = nullptr;
                p->next = newNode;
            }
        }
        for(Node* p = head; p; p = p->next->next){
            Node* randomP = p->random;
            if(randomP){
                p->next->random = randomP->next;
            }else{
                p->next->random = nullptr;
            }
            
        }
        Node* res = head->next;
        for(Node* p = head; p;p = p->next){
            Node* q = p->next;
            p->next = p->next->next;
            if(p->next){
                q->next = q->next->next;
            }else{
                q->next = nullptr;
            }
        }
        return res;
    }
};

解法2

使用hashmap,遍历当前链表,对于每个节点都new一个与它一样的节点,使用hashmap保存这两个节点之间的映射关系。
在将所有的节点相连的过程中,新链表节点的Next指针应该指向hashmap[cur->next],因为cur->next对应的节点也new了一个节点,在hashmap[cur->next]中保存,random同理。新链表节点的random指针应该指向hashmap[cur->random]。

代码

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(!head){
            return NULL;
        }
        unordered_map<Node*,Node*> hashmap;
        Node* p = head;
        while(p){
            hashmap.emplace(p,new Node(p->val));
            p=p->next;
        }
        p = head;
        while(p){
            hashmap[p]->next = hashmap[p->next];
            hashmap[p]->random = hashmap[p->random];
            p=p->next;
        }
        return hashmap[head];
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值