每日精讲:环形链表、两个数组中的交集、随机链表的复制

每日精讲:环形链表、两个数组中的交集、随机链表的复制
 Hello大家好! 很高兴与大家见面! 给生活添点快乐,开始今天的编程之路。



我的博客:<但愿.

我的专栏:C语言题目精讲算法与数据结构C++

欢迎点赞,关注

一 环形链表

1.1题目链接:环形链表II

1.2题目描述:

给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。注意不允许修改 链表。

1.3题目示例:

1.4题目思路:

在我的主页的题目精讲中讲过C语言的方法(快慢指针)C语言相对复杂,这里我们使用C++STL实现。这里使用到STL的set遍历链表如果链表中的节点不在set中就插入(注意这里不是插入节点的值,而是节点的指针,因为节点的值可能有几个相等);如果在就带环,并且该节点就是环入口点。

1.5解决代码

//1cur不在set对象中,就插入到set对象中 //2cur在set对象中就带环,并且该节点就是环入口点 class Solution { public: ListNode *detectCycle(ListNode *head) { set<ListNode*> s; ListNode* cur = head; while(cur) { auto it = s.find(cur);//查找cur是否在set对象中 if(it == s.end())//cur不在set对象中,就插入到set对象中 { s.insert(cur); } else//cur在set对象中就带环,并且该节点就是环入口点 { return *it } cur = cur->next; } return nullptr; } };

二 两个数组中的交集

2.1题目链接:两个数组的交集

2.2题目描述:

给定两个数组 nums1 和 nums2 ,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。

2.3题目示例:

示例 1:输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2]

示例 2:输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[9,4] 解释:[4,9] 也是可通过的

2.4题目思路:

思路1:一个数组的每个值到另一个数组中遍历,这种虽然可行,但是和拿哪个数组中的值到哪个数组中遍历有关例如示例2如果拿nums1中的每个值到nums2中遍历可行,但是如果拿nums2中的每个值到nums1中就会得到结果[9,4,9,4]是不正确的,所以这种方法不行。

思路2(正确思路):先将两个数组去重(要先排序只有排序了才能真正的去重)【去重可用STL中是set;也可以用算法库中的去重算法std::unique】,在拿一个数组中的值分别到另一个数组中找(使用STL->set->count,最后将遍历找到的插入到一个容器中返回即可。

2.5解决代码:

class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { //去重 set<int> s1(nums1.begin(),nums1.end()); set<int> s2(nums2.begin(),nums2.end()); vector<int> v; //将一个数组中的值依次到另一个数组中查找 for(auto e : s1) { if(s2.count(e)) { v.push_back(e);//在另一个数组中插入到一个容器中 } } return v; } };

2.6作用:

从上面来看这个是没有什么作用的,但是现实生活中不只是用来查找交集的,一般是要找交/差/并集,这时候就有著名的对比算法。

两个数组中找交/差/并集的整体思路(对比算法):

【示例】使用对比算法找交集:

class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { set<int> s1(nums1.begin(), nums1.end()); set<int> s2(nums2.begin(), nums2.end()); // 因为set遍历是有序的,有序值,依次⽐较 // ⼩的++,相等的就是交集 vector<int> ret; auto it1 = s1.begin(); auto it2 = s2.begin(); while(it1 != s1.end() && it2 != s2.end()) { if(*it1 < *it2) { it1++; } else if(*it1 > *it2) { it2++; } else { ret.push_back(*it1); it1++; it2++; } } return ret; } };

【对比算法在生活中的应用】

例如我们要更换手机,而之前的手机中有许多的照片是要的,此时怎么办呢?这时候可以买个华为云,将华为云中的照片和之前手机中的照片进行对比,判断是否要导入到华为云中,而照片存在,但是照片可能存在更改,这时候可以比较照片最后的时间。所以这个对比算法在生活中还是有很多用处的。

三 随机链表的复制(两种解决办法C语言[了解思路]、C++)

3.1题目链接:随机链表的复制

3.2题目描述:

给你一个长度为 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 作为传入参数。

3.3题目示例:


3.4题目思路:

3.5解决代码:

【c语言解决代码】注意利用这个了解思路

/**  * Definition for a Node.  * struct Node {  *     int val;  *     struct Node *next;  *     struct Node *random;  * };  */ typedef struct Node Node; //构造一个简单 Node* buyNode(int x) {     Node* newnode = (Node*)malloc(sizeof(Node));     newnode->val = x;     newnode->next=newnode->random = NULL;     return newnode; } //在原链表的基础上拷贝节点(即原链表的每个节点后面拷贝一个一样的节点) void AddNode(Node* head) {     Node* pcur = head;     while(pcur)     {         Node* newnode = buyNode(pcur->val);         Node* next = pcur->next;         newnode->next = next;         pcur->next = newnode;         pcur = next;     } } //设置新节点的random利用关系式 //copy(新节点)->random = pcur(原链表节点)->random->next; void setRandom(Node* head) {     Node* pcur = head;     while(pcur)     {         Node* copy = pcur->next;         if(pcur->random)         {             copy->random = pcur->random->next;         }         pcur = copy->next;     } } struct Node* copyRandomList(struct Node* head) {     if(head == NULL)//如果头节点为空要特殊处理     {         return head;     }     //1在原链表基础上拷贝节点并插入到原链表的每个节点之后     AddNode(head);     //2设置新节点的random     setRandom(head);     //断开新旧链表 //注意这里要返回新链表的根节点,所以这里要定义两个变量 //一个用于储存新链表的根节点位置,一个用于从新链表的根节点位置开始遍历。     Node* pcur = head;     Node* copyHead,*copyTail;     copyHead = copyTail = pcur->next;     while(copyTail->next)     {         pcur = copyTail->next;         copyTail->next = pcur->next;         copyTail = copyTail->next;     }     return copyHead; }

【c++使用STL解决代码】

上面讲了C语言的处理方法,由于出现一个很难处理的问题节点中的random(随机)节点怎么拷贝,如果通过节点中的值进行判断指向关系【如果一个节点的random指向的节点值是1,而节点值为1的节点不止一个有怎么解决呢?显然这种方法是不行的】,如果想走这种匹配关系,那只能暴力遍历,此时时间复杂度为O(N^2)不会,这是因为原链表和拷贝出的链表直接的节点没关系才导致的,C语言的处理方法是先拷贝在原链表中在就导致原链表和拷贝出的链表之间的节点有了关系。那C++怎么处理了,C++所以STL中的map由于储存map(原链表节点,拷贝链表的节点)这不就巧妙的将原链表和拷贝出的链表之间的节点联系起来了吗,可以通过原链表节点得到拷贝对应的节点。

【解决代码】

class Solution { public: Node* copyRandomList(Node* head) { map<Node*, Node*> nodeMap;//由于存在原链表节点和拷贝的节点,从而导致两者之间有关系 Node* copyhead = nullptr,*copytail = nullptr;//由于储存拷贝链表的根节点和遍历拷贝链表 Node* cur = head; while(cur) { if(copytail == nullptr)//如果为空特殊处理 { copyhead = copytail = new Node(cur->val); } else//如果不为空进行尾插 { copytail->next = new Node(cur->val); copytail = copytail->next; } // 原节点和拷⻉节点map kv存储 nodeMap[cur] = copytail; cur = cur->next; } // 处理random cur = head; Node* copy = copyhead; while(cur) { if(cur->random == nullptr)//如果原节点的random为空则拷贝节点的random也为空 { copy->random = nullptr; } else//如果原节点的random不为空则,则使用map[],传入参数原链表节点指针,得到拷贝出的对应节点 { copy->random = nodeMap[cur->random]; } cur = cur->next; copy = copy->next; } return copyhead; } };

本篇文章就到此结束,欢迎大家订阅我的专栏,欢迎大家指正,希望有所能帮到读者更好了算法与数据结构相关知识 ,觉得有帮助的还请三联支持一下~后续会不断更新算法与数据结构相关知识,我们下期再见。

Read more

深度盘点:GitHub 上十大必装 Claude Skill,让你的 AI 助手效率提升 4 倍

深度盘点:GitHub 上十大必装 Claude Skill,让你的 AI 助手效率提升 4 倍

深度盘点:GitHub 上十大必装 Claude Skill,让你的 AI 助手效率提升 4 倍 Claude Code 已经很强大,但如果搭配这些精心设计的 Skills,它将变身超级生产力工具。本文为你深度解析 GitHub 上最受欢迎的 10 大 Claude Skills,帮助你找到最适合的配置方案。 引言:为什么 Claude Skills 如此重要? 在 2025-2026 年,Claude Code 生态经历了爆发式增长。Skills 系统的出现,让 Claude 从一个"对话助手"升级为"专业工具"。通过安装不同的 Skills,你可以:

By Ne0inhk
从安装到代码提交:Git 远程协作中 90% 的问题都能在这里找到答案

从安装到代码提交:Git 远程协作中 90% 的问题都能在这里找到答案

工欲善其事,必先利其器。 目录 * 安装 Git 的步骤: * 本地Git与远程仓库连接及操作全指南 * 一、本地仓库初始化与远程仓库连接 * 1. 初始化本地Git仓库 * 2. 关联远程仓库 * 1. 查看当前分支状态 * 2. 新建本地分支 * 方法1:基于当前分支创建新分支 * 方法2:创建并直接切换到新分支(推荐) * 方法3:基于远程分支创建本地分支 * 3. 切换到已有的本地分支 * 二、分支管理与远程分支同步 * 1. 查看远程分支 * 2. 拉取远程分支到本地 * 三、代码提交与推送到远程仓库 * 1. 常规提交流程 * 2. 简化推送命令 * 四、远程仓库信息查看与更新 * 1. 查看远程仓库详细信息 * 2. 同步远程仓库最新数据 * 五、常见问题解决与优化配置 * 1. 网络与连接问题修复 * 2. 推送大文件或提升传输稳定性

By Ne0inhk
2025电赛E题开源:二维云台激光打靶系统全解析(基于STM32F407+K230)

2025电赛E题开源:二维云台激光打靶系统全解析(基于STM32F407+K230)

2025电赛E题:二维云台激光打靶系统全解析——基于STM32F407的视觉伺服控制 本文详细介绍2025年全国大学生电子设计竞赛E题《二维云台激光打靶系统》的完整实现方案。项目基于STM32F407微控制器,结合视觉追踪、PID控制、步进电机驱动等技术,实现高精度的激光自动瞄准与发射功能。 🎯 项目背景与意义 在自动化控制领域,视觉伺服系统是实现高精度定位与追踪的关键技术。本次分享的项目,源自 2025 年全国大学生电子设计竞赛的赛题,题目要求设计一套二维云台系统,需具备自动识别目标、控制激光精准命中的功能。 该项目历经多重挑战,最终斩获了广东省赛区的省一等奖。由于我在此次比赛中主要负责二维云台激光打靶系统的设计,因此仅针对 25 年电赛 e 题的瞄准模块部分进行解说,自动循迹小车的内容会略过。 这个项目的成功落地,既为电子设计竞赛提供了一套完整的参考方案,也为嵌入式视觉伺服系统的教学与研究提供了宝贵的实践案例。 📊 系统总体设计 系统架构图 二维云台激光打靶系统 ├── 感知层(视觉模块) │ ├── 摄像头采集 │ └── 目标坐标提取 ├── 控制层(主控板

By Ne0inhk
OpenAI 开源模型 gpt-oss 本地部署详细教程

OpenAI 开源模型 gpt-oss 本地部署详细教程

OpenAI 最近发布了其首个开源的开放权重模型gpt-oss,这在AI圈引起了巨大的轰动。对于广大开发者和AI爱好者来说,这意味着我们终于可以在自己的机器上,完全本地化地运行和探索这款强大的模型了。 本教程将一步一步指导你如何在Windows和Linux系统上,借助极其便捷的本地大模型运行框架Ollama,轻松部署和使用 gpt-oss 模型。 一、准备工作:系统配置与性能预期 在开始之前,了解运行环境非常重要。本次部署将在我的个人电脑上进行,下面是推荐配置: * CPU: 现代多核 CPU,如 Intel Core i7 或 AMD Ryzen 7 系列 * 内存 (RAM): 32 GB 或更多 * 显卡 (GPU): 强烈推荐 NVIDIA GeForce RTX 4090 (24 GB 显存)。这是确保大型模型流畅运行与高效微调的理想选择。 * 操作系统: Linux 或 Windows

By Ne0inhk