力扣hot100--链表

链表

1. 2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。

请你将两个数相加,并以相同形式返回一个表示和的链表。

你可以假设除了数字 0 之外,这两个数都不会以 0 开头。

示例 1:

输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[7,0,8]
解释:342 + 465 = 807.

示例 2:

输入:l1 = [0], l2 = [0]
输出:[0]

示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
输出:[8,9,9,9,0,0,0,1]

提示:

  • 每个链表中的节点数在范围 [1, 100] 内
  • 0 <= Node.val <= 9
  • 题目数据保证列表表示的数字不含前导零
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {int t = 0; // 初始化进位为0ListNode *dummy = new ListNode(0); // 创建一个哑节点,初始值为0ListNode* cur = dummy; // 使用指针 cur 指向 dummy// 当 l1 或 l2 不为空时循环while (l1 || l2) {if (l1) {t += l1->val; // 将 l1 的值加到 t 上l1 = l1->next; // 移动到 l1 的下一个节点}if (l2) {t += l2->val; // 将 l2 的值加到 t 上l2 = l2->next; // 移动到 l2 的下一个节点}cur->next = new ListNode(t % 10); // 创建一个新节点,值为 t 的个位数cur = cur->next; // 移动到新创建的节点t = t / 10; // 更新 t 为进位数}// 如果还有进位,创建一个新节点存储进位数if (t) {cur->next = new ListNode(t);}return dummy->next; // 返回结果链表的头节点(跳过哑节点)}
};

2. 19. 删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1], n = 1
输出:[]

示例 3:

输入:head = [1,2], n = 1
输出:[1]

提示:

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz
// 链表+数学计算
/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* removeNthFromEnd(ListNode* head, int n) {int count{};// 删除倒数第n个,即删除第count-n+1ListNode* cNode = head;while(cNode != nullptr){cNode = cNode->next;count++;}ListNode *cNodeX = new ListNode(0);cNodeX->next = head;count = count - n +1;ListNode *node = cNodeX;while(count--){if(0 == count){node->next = node->next->next;break;}node = node->next;}return cNodeX->next;}
};

3. 21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列
// 链表 + 递归/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/class Solution {
public:ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {// 如果 list1 为空,则直接返回 list2,因为没有节点可合并if (!list1) return list2;// 如果 list2 为空,则直接返回 list1,因为没有节点可合并if (!list2) return list1;// 定义一个指针 node,作为合并后的链表头节点ListNode* node;// 比较 list1 和 list2 的当前节点的值,将较小的值加入到合并后的链表中if (list1->val < list2->val) {// 如果 list1 的当前值小于 list2 的当前值,则选择 list1 的节点node = list1;// 继续递归合并 list1 的下一个节点和 list2,设置为 node 的下一个节点list1 = list1->next;} else {// 如果 list2 的当前值小于或等于 list1 的当前值,则选择 list2 的节点node = list2;// 继续递归合并 list2 的下一个节点和 list1,设置为 node 的下一个节点list2 = list2->next;}// 将选中的节点的 next 指针设置为剩余节点递归合并的结果node->next = mergeTwoLists(list1, list2);// 返回合并后的链表头节点return node;}
};

 4. 23. 合并 K 个升序链表

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[1->4->5,1->3->4,2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

提示:

  • k == lists.length
  • 0 <= k <= 10^4
  • 0 <= lists[i].length <= 500
  • -10^4 <= lists[i][j] <= 10^4
  • lists[i] 按 升序 排列
  • lists[i].length 的总和不超过 10^4
// 链表/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:// 方法 1:合并两个有序链表ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {if (!list1) return list2;  // 如果 list1 为空,返回 list2if (!list2) return list1;  // 如果 list2 为空,返回 list1// 创建一个虚拟头节点,便于操作ListNode* node = new ListNode(0);ListNode* tail = node;// 遍历 list1 和 list2,合并两个链表while (list1 && list2) {if (list1->val < list2->val) {tail->next = list1; // 将 list1 的当前节点接入合并链表list1 = list1->next; // 移动 list1 指针到下一个节点} else {tail->next = list2; // 将 list2 的当前节点接入合并链表list2 = list2->next; // 移动 list2 指针到下一个节点}tail = tail->next; // 移动合并链表的尾节点}// 将剩余的链表部分直接连接到合并链表的尾部tail->next = list1 ? list1 : list2;// 返回合并后的链表头节点(去除虚拟头节点)return node->next;}// 方法 2:合并多个链表ListNode* mergeKLists(vector<ListNode*>& lists) {int k = lists.size();ListNode* node{}; // 初始合并链表为空// 逐个合并链表for (int i = 0; i < k; ++i) {node = mergeTwoLists(node, lists[i]);}return node; // 返回最终合并后的链表头节点}
};

5. 141. 环形链表

给你一个链表的头节点 head ,判断链表中是否有环。

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

如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:false
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos 为 -1 或者链表中的一个 有效索引 。

// 双指针方法
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;                // 节点的值
 *     ListNode *next;        // 指向下一个节点的指针
 *     ListNode(int x) : val(x), next(NULL) {} // 构造函数
 * };
 */
class Solution {
public:
    // 方法:检查链表是否有环
    bool hasCycle(ListNode *head) {
        ListNode *slow = head;  // 慢指针,初始指向链表头
        ListNode *fast = head;  // 快指针,初始指向链表头

        // 当快指针和快指针的下一个节点存在时,继续循环
        while(fast && fast->next){
            slow = slow->next;           // 慢指针每次移动一步
            fast = fast->next->next;     // 快指针每次移动两步

            // 如果慢指针和快指针相遇,说明链表中存在环
            if(slow == fast){
                return true;  // 有环,返回true
            }
        }

        return false; // 无环,返回false
    }
};
 

解释: 

  • 慢指针和快指针:慢指针每次移动一步,而快指针每次移动两步。如果链表中有环,快指针最终会追上慢指针。
  • 循环条件:在 while 循环中,我们确保快指针和快指针的下一个节点都不为空,以避免访问空指针。
  • 相遇检测:如果在某个时刻,慢指针和快指针相遇,则说明链表中存在环。返回 true
  • 无环返回:如果快指针到达链表的末尾,说明链表没有环,返回 false

6. 142. 环形链表 II

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

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

不允许修改 链表。

示例 1:

输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

输入:head = [1,2], pos = 0
输出:返回索引为 0 的链表节点
解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

输入:head = [1], pos = -1
输出:返回 null
解释:链表中没有环。

提示:

  • 链表中节点的数目范围在范围 [0, 104] 内
  • -105 <= Node.val <= 105
  • pos 的值为 -1 或者链表中的一个有效索引

// 双指针 + 数学方法
// 核心:a = c + (n−1)(b + c) 的等量关系
// 我们会发现:从相遇点到入环点的距离加上 (n−1) 圈的环长,恰好等于从链表头部到入环点的距离
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;                // 节点的值
 *     ListNode *next;        // 指向下一个节点的指针
 *     ListNode(int x) : val(x), next(NULL) {} // 构造函数
 * };
 */
class Solution {
public:
    // 方法:检测链表中的环并返回环的起始节点
    ListNode *detectCycle(ListNode *head) {
        // 检查链表是否为空或节点不足以形成环
        if(!head || !head->next || !head->next->next) return {};

        ListNode* slow = head;  // 慢指针,初始指向链表头
        ListNode* fast = head;  // 快指针,初始指向链表头

        // 使用快慢指针检测是否存在环
        while(fast && fast->next) {
            slow = slow->next;           // 慢指针每次移动一步
            fast = fast->next->next;     // 快指针每次移动两步

            // 如果慢指针和快指针相遇,说明存在环
            if(slow == fast) {
                break;  // 跳出循环
            }
        }

        // 如果慢指针没有与快指针相遇,则说明没有环
        if(slow != fast) return {};  // 返回空指针

        // 从相遇点重新初始化慢指针到链表头部
        slow = head;

        // 同时移动慢指针和快指针,直到相遇
        while(slow != fast) {
            slow = slow->next;  // 慢指针每次移动一步
            fast = fast->next;  // 快指针每次移动一步
        }

        // 返回相遇点,即环的起始节点
        return slow;
    }
};
 

解释: 

  • 检测环的存在:首先使用快慢指针方法检测链表中是否存在环。如果慢指针和快指针相遇,说明链表中有环。
  • 重新定位慢指针:当检测到环时,将慢指针重新指向链表头部。
  • 寻找环的起始节点:然后,慢指针和快指针同时向前移动,每次移动一步。它们会在环的起始节点相遇,因为从链表头到环的起始节点的距离与从相遇点到环的起始节点的距离是相等的。
  • 返回环的起始节点:当两指针再次相遇时,返回这个节点,即为环的起始节点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/442385.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【word脚注】双栏设置word脚注,脚注仅位于左栏,右栏不留白

【word脚注】双栏设置word脚注&#xff0c;脚注仅位于左栏&#xff0c;右栏不留白 调整前效果解决方法调整后效果参考文献 调整前效果 调整前&#xff1a;脚注位于左下角&#xff0c;但右栏与左栏内容对其&#xff0c;未填充右下角的空白区域 解决方法 备份源文件复制脚注内…

git创建新分支

git创建新分支 1.先在gitLab上New branch. 2.本地右键git小乌 - /切换/检出-创建新分支&#xff0c;分支名称和上一步创建的一样。 最后记得改个文件提交下&#xff0c;看看gitLab上是否提交成功。

蝶形激光器驱动(温控精度0.002°C 激光电流分辨率5uA)

蝶形半导体激光器驱动电流的稳定性直接决定了其输出波长的稳定性,进而影响检测精度.为了满足气体浓度检测中对激光器输出波长稳定可调的要求,设计了数字与模拟电路混合的恒流驱动电路.STM32为主控芯片数控模块完成扫描AD/DA转换;模拟电路主要由负反馈运算放大、高精度CMOS管和反…

22.第二阶段x86游戏实战2-背包遍历REP指令详解

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

rtmp协议转websocketflv的去队列积压

websocket server的优点 websocket server的好处&#xff1a;WebSocket 服务器能够实现实时的数据推送&#xff0c;服务器可以主动向客户端发送数据 1 不需要客户端不断轮询。 2 不需要实现httpserver跨域。 在需要修改协议的时候比较灵活&#xff0c;我们发送数据的时候比较…

【网络安全】利用XSS、OAuth配置错误实现token窃取及账户接管 (ATO)

未经许可,不得转载。 文章目录 正文正文 目标:target.com 在子域sub1.target.com上,我发现了一个XSS漏洞。由于针对该子域的漏洞悬赏较低,我希望通过此漏洞将攻击升级至app.target.com,因为该子域的悬赏更高。 分析认证机制后,我发现: sub1.target.com:使用基于Cook…

微信小程序——音乐播放器

一、界面设计 播放页面&#xff1a; 显示当前播放歌曲的封面图片、歌曲名称、歌手名称。有播放 / 暂停按钮、上一首、下一首按钮。进度条显示播放进度&#xff0c;可以拖动进度条调整播放位置。音量调节滑块。 歌曲列表页面&#xff1a; 展示歌曲列表&#xff0c;包括歌曲名称、…

C++——STL简介

目录 一、什么是STL 二、STL的版本 三、STL的六大组件 没用的话..... 不知不觉两个月没写博客了&#xff0c;暑假后期因为学校的事情在忙&#xff0c;开学又在准备学校的java免修&#xff0c;再然后才继续开始学C&#xff0c;然后最近打算继续写博客沉淀一下最近学到的几周…

构建高效团队,内部CRM系统的益处详解

内部CRM系统的最大优势之一是它能够集中并系统化客户信息&#xff0c;包括联系方式、购买历史、偏好设置、服务记录等。这种集中式的数据管理使企业能够快速响应客户需求&#xff0c;预测客户行为&#xff0c;提供个性化的服务或产品。更重要的是&#xff0c;它有助于建立一个统…

【PyTorch】图像分割

图像分割是什么 Image Segmentation 将图像每一个像素分类 图像分割分类 超像素分割&#xff1a;少量超像素代替大量像素&#xff0c;常用于图像预处理语义分割&#xff1a;逐像素分类&#xff0c;无法区分个体实例分割&#xff1a;对个体目标进行分割全景分割&#xff1a;…

信息学奥赛使用的编程IDE:Dev-C++ 安装指南

信息学奥赛&#xff08;NOI&#xff09;作为全国性的编程竞赛&#xff0c;要求参赛学生具备扎实的编程能力&#xff0c;而熟练使用适合的编程工具则是学习与竞赛的基础。在众多编程环境中&#xff0c;Dev-C IDE 因其简洁、轻量、支持C编程等特点&#xff0c;成为许多参赛者的常…

Pikachu-SSRF(curl / file_get_content)

SSRF SSRF是Server-side Request Forge的缩写&#xff0c;中文翻译为服务端请求伪造。产生的原因是由于服务端提供了从其他服务器应用获取数据的功能且没有对地址和协议等做过滤和限制。常见的一个场景就是&#xff0c;通过用户输入的URL来获取图片。这个功能如果被恶意使用&am…

AI先驱荣获2024诺贝尔物理学奖

瑞典皇家科学院10月8日宣布&#xff0c;将2024年诺贝尔物理学奖授予John J. Hopfield和Geoffrey E. Hinton&#xff0c;以表彰他们利用人工神经网络实现机器学习的奠基性发现和发明。 John J. Hopfield&#xff08;约翰J霍普菲尔德&#xff09;美国新泽西州普林斯顿大学 Geoff…

1500元买哪款显卡好?对比一下,差别明显

在游戏过程中&#xff0c;显卡负责渲染游戏画面&#xff0c;将其转化为可视化的图像&#xff0c;并快速显示在屏幕上&#xff0c;确保游戏运行的流畅性和画面的质量。所以对于游戏电脑来说&#xff0c;显卡的重要性尤为突出。虽说在最近几年&#xff0c;显卡市场的“消费升级”…

ssm淘乐乐员工购物商城

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 目 录 III 第1章 绪论 1 1.1 课题背景 1 1.2 课题意义 1 1.3 研究内容 2 第2章 开发环境与技术 3 …

时序论文17|ICML24 SAMformer:华为新奇视角讨论Transformer时序预测时的收敛优化问题

论文标题&#xff1a;SAMformer: Unlocking the Potential of Transformers in Time Series Forecasting with Sharpness-Aware Minimization and Channel-Wise Attention 论文链接&#xff1a;https://arxiv.org/abs/2402.10198 代码链接&#xff1a;https://github.com/rom…

计算机网络——http和web

无状态服务器——不维护客户端 怎么变成有状态连接 所以此时本地建立代理—— 若本地缓存了——但是服务器变了——怎么办&#xff1f;

今日指数项目day8实战补充 - 角色处理器功能实现(上)

角色处理器 2.1 分页查询当前角色信息 1&#xff09;原型效果 2&#xff09;接口说明 功能描述&#xff1a; 分页查询当前角色信息 服务路径&#xff1a; /api/roles 服务方法&#xff1a;Post请求参数格式&#xff1a; {"pageNum":1,"pageSize":10 }响…

Vue 项目文件大小优化

优化逻辑 任何优化需求&#xff0c;都有一个前提&#xff0c;即可衡量。 那 Vue 加载速度的优化需求&#xff0c;本质上是要降低加载静态资源的大小。 所以&#xff0c;优化前&#xff0c;需要有一个了解项目现状的资源加载大小情况。 主要分 3 步走&#xff1a; 找到方法测…

Ubuntu24.04远程开机

近来在几台机器上鼓捣linux桌面&#xff0c;顺便研究一下远程唤醒主机。 本篇介绍Ubuntu系统的远程唤醒&#xff0c;Windows系统的唤醒可搜索相关资料。 依赖 有远程唤醒功能的路由器&#xff08;当前一般都带这个功能&#xff09;有线连接主机&#xff08;无线连接有兴趣朋友…