当前位置: 首页 > news >正文

LeetCode 面试经典 150_链表_随机链表的复制(59_138_C++_中等)

LeetCode 面试经典 150_链表_随机链表的复制(59_138_C++_中等)

    • 题目描述:
    • 输入输出样例:
    • 题解:
      • 解题思路:
        • 思路一(哈希表):
        • 思路二(迭代 + 节点拆分):
      • 代码实现
        • 代码实现(思路一(哈希表)):
        • 代码实现(思路二(迭代 + 节点拆分)):
        • 以思路二为例完成代码调试

题目描述:

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

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

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

返回复制链表的头节点。

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

val:一个表示 Node.val 的整数。
random_index:随机指针指向的节点索引(范围从 0 到 n-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]]

提示:
0 <= n <= 1000
-104 <= Node.val <= 104
Node.random 为 null 或指向链表中的节点。

题解:

解题思路:

思路一(哈希表):

1、我们可以直接将原链表和复制链表中对应的结点存储在哈希表中,这样我们就可以直接通过原地址的 next 和 random 来更新复制链表的指向。
例:
在这里插入图片描述

2、具体思路如下:
① 创建一个哈希表用于存储两个链表中每个结点地址的对应关系。
② 遍历原链表的同时创建复制链表的 val ,并使用哈希表记录原链表结点地址和复制链表地址的对应关系。
③ 用过哈希表更新复制链表的 next 和 random指向。

3、复杂度分析
① 时间复杂度:O(N),N代表原链表所含结点的数量。创建复制结点的时间复杂度为N,更新结点的指向的时间消耗为N,所以时间复杂度为O(N)。
② 空间复杂度:O(N),,使用了一个额外的哈希表来存储结点地址的对应关系(除存储答案所需空间)。

思路二(迭代 + 节点拆分):

1、我们可以将复制结点创建出来之后直接插入在原结点后边。这样我们在更新random的指向时就可以直接通过原结点random的指向来更新复制结点random的指向。
例:
在这里插入图片描述
2、具体思路如下:
① 在每个原结点后边创建一个复制结点并插入,将复制结点的random设置为nullptr。
② 遍历创建后的链表,更新复制结点的random的指向。
③ 将复制结点查下来,将原链表进行复原。

3、复杂度分析
① 时间复杂度:O(N),N代表原链表所含结点的数量。创建复制结点的时间复杂度为N,更新结点的指向的时间消耗为N,所以时间复杂度为O(N)。
② 空间复杂度:O(1),除存储答案所需空间。

代码实现

代码实现(思路一(哈希表)):
class Solution1 {
public:// 复制带有随机指针的链表Node* copyRandomList(Node* head) {// 创建一个unordered_map来存储原链表节点和新链表节点的映射关系unordered_map<Node*, Node*> map;// 第一步:遍历原链表,为每个节点创建一个新的节点Node *curNode = head;while (curNode != nullptr) {// 为当前节点创建一个新的节点,并将原节点和新节点的映射添加到map中Node *newNode = new Node(curNode->val);map[curNode] = newNode;// 移动到下一个节点curNode = curNode->next;}// 第二步:重新遍历原链表,设置新节点的 next 和 random 指针curNode = head;while (curNode != nullptr) {// 为新节点设置 next 和 random 指针,map[curNode->next] 和 map[curNode->random] 通过原节点找到对应的新节点map[curNode]->next = map[curNode->next];  // 设置新节点的 next 指针map[curNode]->random = map[curNode->random];  // 设置新节点的 random 指针// 移动到下一个节点curNode = curNode->next;}// 返回新链表的头节点return map[head];}
};
代码实现(思路二(迭代 + 节点拆分)):
class Solution2 {
public:Node* copyRandomList(Node* head) {if (head == nullptr) {return nullptr;}Node* head1 = head;// 创建复制的结点插入原链表while (head1 != nullptr) {Node* newNode = new Node(head1->val);newNode->next = head1->next;head1->next = newNode;head1 = head1->next->next;}//更新head1指向首节点head1 = head;// 修改新创建结点random的指向while (head1 != nullptr) {if (head1->random != nullptr) {head1->next->random = head1->random->next;}head1 = head1->next->next;}//将链表一和链表二进行拆分,不使用新的头节点 head1 = head;Node* head2 = head->next;Node* tmp_head2 = head->next;while (head2->next != nullptr) {head1->next = head1->next->next;head2->next = head1->next->next;head1 = head1->next;head2 = head2->next;}head1->next = nullptr;return tmp_head2;//将链表一和链表二进行拆分//使用一个新的头节点来链接拆分的链表二 //	Node *dummyNode=new Node(0);//	head1=head;//	Node *head2=dummyNode;//	while(head1!=nullptr){//		head2->next=head1->next;//		head2=head1->next;//		head1->next=head2->next;//		head1=head2->next;//	}//	head2=dummyNode->next;//	delete dummyNode;//	return head2;}
};
以思路二为例完成代码调试
#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;class Node{
public:int val;Node *next;Node *random;Node(int _val){val=_val;next=NULL;random=NULL;}
};/*创建随机链表*/ 
Node *createNode(vector<vector<int>> &arr){Node *head=nullptr,*tail=nullptr;int n=0;//id_adress保存每个结点的序号和id,使其对应 unordered_map<int,Node *> id_adress;//采用尾插法先创建一个单链表,先使得random=nullptr for(const auto &i:arr){if(head==nullptr){head=tail=new Node(i[0]);}else{tail->next=new Node(i[0]);tail=tail->next;}id_adress[n]=tail;++n;}//将random通过adress_id进行赋值,-1代表nullptr tail=head;for(const auto &i:arr){if(i[1]==-1){tail=tail->next;continue;}tail->random=id_adress[i[1]];tail=tail->next;}return head;
}class Solution1 {
public:// 复制带有随机指针的链表Node* copyRandomList(Node* head) {// 创建一个unordered_map来存储原链表节点和新链表节点的映射关系unordered_map<Node*, Node*> map;// 第一步:遍历原链表,为每个节点创建一个新的节点Node *curNode = head;while (curNode != nullptr) {// 为当前节点创建一个新的节点,并将原节点和新节点的映射添加到map中Node *newNode = new Node(curNode->val);map[curNode] = newNode;// 移动到下一个节点curNode = curNode->next;}// 第二步:重新遍历原链表,设置新节点的 next 和 random 指针curNode = head;while (curNode != nullptr) {// 为新节点设置 next 和 random 指针,map[curNode->next] 和 map[curNode->random] 通过原节点找到对应的新节点map[curNode]->next = map[curNode->next];  // 设置新节点的 next 指针map[curNode]->random = map[curNode->random];  // 设置新节点的 random 指针// 移动到下一个节点curNode = curNode->next;}// 返回新链表的头节点return map[head];}
};int main(){vector<vector<int>> a={{7,-1},{13,0},{11,4},{10,2},{1,0}};Solution1 s;//创建原随机链表Node *head =createNode(a);//随机链表的复制Node *test =s.copyRandomList1(head);//只输出复制随机链表的random指向while(test!=nullptr){if(test->random!=nullptr){cout<<test->random->val<<"   ";}else{cout<<"nullptr   ";}test=test->next;}cout<<"null"; return 0;
}

LeetCode 面试经典 150_链表_随机链表的复制(59_138)原题链接
欢迎大家和我沟通交流(✿◠‿◠)

http://www.dtcms.com/a/524386.html

相关文章:

  • WPS 365政务版亮相2025数博会,AI生成公文可用度达90%
  • 判断网站是否被k校园类网站模板
  • wordpress删除站点怎样给建设的网站提意见
  • Zabbix Agent 安装
  • RTX5060TI 安装C++版本的onnxruntime(GPU版本)
  • MCP(trae)+ IDA-提高干活效率
  • Spring Boot微服务健康检测:保障系统稳定性的关键实践
  • 利用Java API与HDFS进行交互
  • Linux 中修改 IP 地址为 静态 IP 地址
  • 一团网站建设个人网页设计作业
  • 做网站商城赔了8万卢松松网站源码
  • 界面控件Kendo UI for Angular 2025 Q3亮点 - 全新的AI编码助手
  • 鸿蒙HarmonyOS ArkUI 状态管理装饰器详解
  • 旅游景点网站建设防疫测温健康码核验一体机
  • 一套试卷——数据结构(2020数据结构B)
  • 性能测试之性能监控详解
  • 阿里云国际站GPU:怎么通过通过VNC连接实例?
  • Elasticsearch 实现类 GitHub 关键词搜索与高亮列表展示
  • 怎么查看网站外链效果宁波seo推广哪家好
  • C#窗体实现自定义数字控件
  • ComposeView杂记(持续更新)
  • Redis的有序集合的底层实现
  • 海康威视云台相机的python sdk使用(云台控制)
  • REST 表征状态转移
  • React 04
  • 深度学习常用优化器解析
  • 浙江网站建设cms哪家建站公司好
  • 动态识别文件夹下flask接口
  • 【参赛心得】鸿蒙参赛心得:从零到获奖的成长之路
  • java 程序Apache log4j JDBCAppender SQL注入漏洞(CVE-2022-23305)