发布时间:2026/8/26 16:04:10
【算法从零到千】【59-65】链表专题 1. 两数相加2. 两数相加https://leetcode.cn/problems/add-two-numbers/https://leetcode.cn/problems/add-two-numbers/给你两个 非空 的链表表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的并且每个节点只能存储 一位 数字。请你将两个数相加并以相同形式返回一个表示和的链表。你可以假设除了数字 0 之外这两个数都不会以 0 开头写法迭代class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { int carry0,all0; ListNode* pheadnew ListNode(0);ListNode* curphead; while(l1l2) { alll1-vall2-valcarry; if(all10){carry1;all%10;} else{carry0;} cur-nextnew ListNode(all); curcur-next; l1l1-next;l2l2-next;all0; } while(l1||l2) { if(l1){alll1-valcarry; l1l1-next;} if(l2){alll2-valcarry; l2l2-next;} if(all10){carry1;all%10;} else{carry0;} cur-nextnew ListNode(all);all0; curcur-next; } if(carry1) { cur-nextnew ListNode(1); curcur-next; } curphead-next; delete phead; return cur; } };优化写法class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { // 构造哑巴节点 dummy最后返回 dummy.next, 以方便处理新链表的头节点。 ListNode* dummy new ListNode(0); ListNode* node dummy; // node 一直会变化前进 int carrier 0; // 进位 // 只要有没走到头的链表或者进位不为 0 就一直前进。 while (l1 || l2 || carrier) { // 求和考虑可能有链表走到头 int sum (l1 ? l1-gt;val : 0) (l2 ? l2-gt;val : 0) carrier; // 在尾部添加节点 node-gt;next new ListNode(sum % 10); node node-gt;next; // 更新进位并向两个链表尾部前进 carrier sum / 10; if (l1) l1 l1-gt;next; if (l2) l2 l2-gt;next; } ListNode* result dummy-gt;next; // 保存结果链表的头节点 delete dummy; // 释放哑节点的内存 return result; } };2. 删除链表的倒数第N个节点19. 删除链表的倒数第 N 个结点https://leetcode.cn/problems/remove-nth-node-from-end-of-list/https://leetcode.cn/problems/remove-nth-node-from-end-of-list/给你一个链表删除链表的倒数第n个结点并且返回链表的头结点写法一双指针class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode* curhead;ListNode* prevnullptr; int size0; while(cur) {size;curcur-next;} curhead;int aimsize-n; while(aim--) { prevcur; curcur-next; } if(curhead) return head-next; if(head-next) prev-nextcur-next; else return nullptr; return head; } };写法二快慢指针class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { // 由于可能会删除链表头部用哨兵节点简化代码 ListNode dummy{0, head}; ListNode* left dummy; ListNode* right dummy; while (n--) { right right-next; // 右指针先向右走 n 步 } while (right-next) { left left-next; right right-next; // 左右指针一起走 } // 左指针的下一个节点就是倒数第 n 个节点 ListNode* nxt left-next; left-next left-next-next; delete nxt; return dummy.next; } };3. 排序链表148. 排序链表https://leetcode.cn/problems/sort-list/https://leetcode.cn/problems/sort-list/给你链表的头结点head请将其按 升序 排列并返回 排序后的链表写法一STLclass Solution { public: ListNode* sortList(ListNode* head) { multimapint,ListNode* hash; ListNode* curhead; while(cur) { hash.insert({cur-val,cur}); curcur-next; } ListNode* pheadnew ListNode(0);curphead; for(auto e:hash) { cur-nexte.second; curcur-next; } cur-nextnullptr; return phead-next; } };写法二归并排序class Solution { public: ListNode* sortList(ListNode* head) { return mergeSort(head); } /** * 对给定的链表进行归并排序 */ ListNode* mergeSort(ListNode* head){ // 如果链表为空或只有一个节点无需排序直接返回 if(!head || !head-gt;next){ return head; } // 获取链表的中间节点分别对左右子链表进行排序 ListNode* mid getMid(head); ListNode* rightSorted mergeSort(mid-gt;next); // 排序右子链表 if(mid)mid-gt;next nullptr; // 断开两段子链表 ListNode* leftSorted mergeSort(head); // 排序左子链表 return mergeTwoLists(leftSorted, rightSorted); // 两个子链表必然有序合并两个有序的链表 } /** * 获取以head为头节点的链表中间节点 * 如果链表长度为奇数返回最中间的那个节点 * 如果链表长度为偶数返回中间靠左的那个节点 */ ListNode* getMid(ListNode* head){ if(!head)return head; ListNode* slow head, *fast head-gt;next; // 快慢指针慢指针初始为 while(fast ! nullptr amp;amp; fast-gt;next ! nullptr) { fast fast-gt;next-gt;next; // 快指针每次移动两个节点 slow slow-gt;next; // 慢指针每次移动一个节点 } return slow; // 快指针到达链表尾部时慢指针即指向中间节点 } /** * 合并两个有序链表list1和list2 */ ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { ListNode* dummy new ListNode(); // 伪头节点用于定位合并链表的头节点 ListNode* node dummy; // 新链表当前的最后一个节点初始为伪头节点 // 直到两个链表都遍历完了合并结束 while(list1 ! nullptr || list2 ! nullptr){ int val1 list1 nullptr ? 50001 : list1 -gt; val; // 如果链表1已经遍历完val1取最大值保证链表2的节点被选择到 int val2 list2 nullptr ? 50001 : list2 -gt; val; // 如果链表2已经遍历完val2取最大值保证链表1的节点被选择到 if(val1 lt; val2){ // 链表1的节点值更小加入到合并链表并更新链表1指向的节点 node -gt; next list1; list1 list1 -gt; next; }else{ // 链表2的节点值更小加入到合并链表并更新链表2指向的节点 node -gt; next list2; list2 list2 -gt; next; } node node -gt; next; // 更新合并链表当前的最后一个节点指向 } return dummy -gt; next; // 伪头节点的下一个节点即为合并链表的头节点 } };4. 重排链表4LCR 026. 重排链表https://leetcode.cn/problems/LGjMqU/https://leetcode.cn/problems/LGjMqU/给定一个单链表L的头节点head单链表L表示为L0 → L1 → … → Ln-1 → Ln请将其重新排列后变为L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …不能只是单纯的改变节点内部的值而是需要实际的进行节点交换写法一STL映射class Solution { public: void reorderList(ListNode* head) { if (!head-next) return; //处理边界 maplt;int,ListNode*gt; index;//记录位置 ListNode* curhead;int i0; while(cur) { index[i]cur; curcur-gt;next; } i--;//保证索引正确 curhead;int j1;//前后挨个插入 while(jlt;i) { cur-gt;nextindex[i--]; curcur-gt;next; if(i!j)//当ij只执行一次 {cur-gt;nextindex[j]; curcur-gt;next;} } cur-gt;nextnullptr; } };写法二反转三指针class Solution { public: void reorderList(ListNode* head) { ListNode* dummmy new ListNode(0); dummmy-next head; ListNode* slow dummmy; ListNode* fast dummmy; while (fast ! nullptr fast-next ! nullptr) { slow slow-next; fast fast-next-next; } delete dummmy; dummmy nullptr; ListNode* headB slow-next; slow-next nullptr; ListNode* p2 reverseList(headB); ListNode* p1 head; ListNode* p3 nullptr; while (p2 ! nullptr) { p3 p1-next; p1-next p2; p1 p2; p2 p3; } } ListNode* reverseList(ListNode* head) { if (head nullptr) { return head; } ListNode* left nullptr; ListNode* cur head; ListNode* right nullptr; while (cur ! nullptr) { right cur-gt;next; cur-gt;next left; left cur; cur right; } return left; } };5. 两两交换链表中的节点24. 两两交换链表中的节点https://leetcode.cn/problems/swap-nodes-in-pairs/https://leetcode.cn/problems/swap-nodes-in-pairs/给你一个链表两两交换其中相邻的节点并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题即只能进行节点交换。写法一迭代class Solution { public: ListNode* swapPairs(ListNode* head) { if(!head||!head-next) return head; ListNode* curhead-next;ListNode* prevhead; //完成前两个 prev-nextcur-next; cur-nexthead;headcur; //后面再规律处理 curprev; prevhead;ListNode* prevvnullptr; while(cur-nextcur-next-next) { //规律移动 if(cur-nextcur-next-next){ prevvcur; curcur-next-next; prevprev-next-next; } //交换流程 prev-nextcur-next; cur-nextprev; prevv-nextcur; //保持cur与prev的前后关系 curprev; prevprevv-next; } //如果还剩下则为一个不用交换 return head; } };写法二递归class Solution { public: ListNode* swapPairs(ListNode* head) { if (head nullptr || head-next nullptr) { return head; } ListNode* node1 head; ListNode* node2 head-gt;next; ListNode* node3 node2-gt;next; node1-gt;next swapPairs(node3); // 1 指向递归返回的链表头 node2-gt;next node1; // 2 指向 1 return node2; // 返回交换后的链表头节点 } };6. 合并K个升序链表23. 合并 K 个升序链表https://leetcode.cn/problems/merge-k-sorted-lists/https://leetcode.cn/problems/merge-k-sorted-lists/给你一个链表数组每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中返回合并后的链表。写法一STL映射class Solution { public: ListNode* mergeKLists(vectorListNode* lists) { if(lists.size()0)return nullptr; if(lists.size()1)return lists[0]; //用哈希记录索引和节点地址 multimapint,ListNode* nodemap; for(auto e:lists) { ListNode* cure; while(cur) { nodemap.insert({cur-val,cur}); curcur-next; } } //重组链表 ListNode* pheadnew ListNode(0);ListNode* curphead; for(auto e:nodemap) { cur-nexte.second; curcur-next; } cur-nextnullptr; return phead-next; } };写法二优先级队列⭐⭐class Solution { public: ListNode* mergeKLists(vectorListNode* lists) { auto cmp [](const ListNode* a, const ListNode* b) { return a-val b-val; // 最小堆 }; priority_queueListNode*, vectorListNode*, decltype(cmp) pq; for (auto head : lists) { if (head) { pq.push(head); // 把所有非空链表的头节点入堆 } } ListNode dummy{}; // 哨兵节点作为合并后链表头节点的前一个节点 auto cur amp;dummy; while (!pq.empty()) { // 循环直到堆为空 auto node pq.top(); // 剩余节点中的最小节点 pq.pop(); if (node-gt;next) { // 下一个节点不为空 pq.push(node-gt;next); // 下一个节点有可能是最小节点入堆 } cur-gt;next node; // 把 node 添加到新链表的末尾 cur cur-gt;next; // 准备合并下一个节点 } return dummy.next; // 哨兵节点的下一个节点就是新链表的头节点 } };非常重要7. K个一组翻转链表25. K 个一组翻转链表https://leetcode.cn/problems/reverse-nodes-in-k-group/https://leetcode.cn/problems/reverse-nodes-in-k-group/给你链表的头节点head每k个节点一组进行翻转请你返回修改后的链表。k是一个正整数它的值小于或等于链表的长度。如果节点总数不是k的整数倍那么请将最后剩余的节点保持原有顺序。你不能只是单纯的改变节点内部的值而是需要实际进行节点交换。写法一栈class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { if (k 1) return head; stackListNode* st; ListNode* pheadnew ListNode(0);ListNode* pcurphead; ListNode* curhead; //统计节点数量 int size0; while(cur){curcur-next;size;} //按k的数量依次处理 int n0,count0;curhead; while(countksize) { while(nkcur) { st.push(cur); curcur-next; n;count; } while(!st.empty()) { pcur-nextst.top(); st.pop(); pcurpcur-next; } n0; } //处理末尾情况 if(countsize) pcur-nextcur; else pcur-nextnullptr; curphead-gt;next; delete phead; return cur; } };写法二递归class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { ListNode *p head; for(int i 0; i k; i) { if(!p) return head; p p-next; } ListNode *q head; ListNode *pre nullptr; while(q ! p) { ListNode *tmp q-gt;next; q-gt;next pre; pre q; q tmp; } head-gt;next reverseKGroup(p, k); return pre; } };

相关新闻

2026/8/26 16:04:10

RevokeMsgPatcher:微信QQ防撤回补丁怎么用?

RevokeMsgPatcher:微信QQ防撤回补丁怎么用? 【免费下载链接】RevokeMsgPatcher :trollface: A hex editor for WeChat/QQ/TIM - PC版微信/QQ/TIM防撤回补丁(我已经看到了,撤回也没用了) 项目地址: https://gitcode.c…

2026/8/26 16:04:10

3 步免费把 NCM 加密音乐转成 MP3:ncmdump 离线转换入门教程

3 步免费把 NCM 加密音乐转成 MP3:ncmdump 离线转换入门教程 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump ncmdump 是一款完全免费、开源的本地加密音乐转换工具,把网易云 NCM 加密文件转成通用 MP3。全程无…

2026/8/26 17:05:06

飞书 CLI 联动 Codex,从需求文档到代码的端到端自动化

从飞书文档到可运行代码:Codex 自动化流水线实战 在传统开发流程中,需求从产品经理的飞书文档流转到开发者的 IDE,往往伴随着大量的人工转录工作。复制粘贴需求细节、手动拆解任务、再逐行编写代码,这个过程不仅耗时,还…

2026/8/26 17:05:06

基于SpringBoot2+vue2的在线考试与学习交流系统

1. Base64 编码解锁技能,猴子打野出装需 5 大米 ,才能真正驾驭“猴三棒”的暴力美学 鞋子/小野刀/贪婪之噬/暗影战斧/泣血之刃/名刀司命 铭文组合为8夺萃、1狩猎、1兽痕、5祸源、5无双、10鹰眼 复制打开获取源代码:https://fifteen.xiaobias.…

2026/8/26 17:05:06

所见即所得前端开发,Codex 内置浏览器让改图更直观

告别切屏焦虑:Codex 内置浏览器重塑前端工作流 对于前端开发者而言,最打断心流的瞬间往往不是逻辑复杂,而是频繁的上下文切换。传统开发模式下,我们像是在走钢丝:左边是代码编辑器,右边是浏览器预览窗口。改…

2026/8/26 17:05:06

Codex 桌面端实战,手把手教你从零创建 Spring Boot 项目

对于习惯图形化操作的后端开发者来说,命令行工具虽然强大,但往往增加了学习成本。Codex 桌面端的出现,恰好填补了“自然语言交互”与“本地文件操作”之间的空白。它不仅仅是一个聊天窗口,更是一个能直接读写你硬盘、执行终端命令…

2026/8/26 17:05:05

基于SpringBoot2+Vue2的常规应急物资管理系统

1. Base64 编码解锁技能,猴子打野出装需 5 大米 ,才能真正驾驭“猴三棒”的暴力美学 鞋子/小野刀/贪婪之噬/暗影战斧/泣血之刃/名刀司命 铭文组合为8夺萃、1狩猎、1兽痕、5祸源、5无双、10鹰眼 复制打开获取源代码:https://fifteen.xiaobias.…

2026/8/26 17:00:05

Hadoop 分布式集群实战 2—— Hadoop 高可用架构

1 HDFS‑HA 核心组件 2 台 NameNode Active NameNode:对外处理客户端读写,唯一写元数据Standby NameNode:热备,不接收客户端请求,实时同步元数据,故障时升级为 Active JournalNode 集群(JN&…

2026/8/26 9:13:28

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/25 11:48:27

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/25 16:56:43

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/26 0:04:32

Python random 模块常用函数详解:从入门到实战

目录 1. 引言2. 准备工作3. 基础随机函数4. 序列相关函数5. 随机种子与复现6. 实战案例7. 注意事项8. 常见问题与排查9. 总结 1. 引言 摘要: 本文系统介绍 Python 标准库 random 模块中最常用的随机数生成函数。内容涵盖基础随机函数(random()、unifor…

2026/8/26 1:19:35

JSON总结

JSON概念 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,主要用于跟服务器进行交换数据。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、C、C#、Java、JavaScr…

2026/8/26 1:19:35

保存连接sse 是什么原理,为什么不会一直请求

“保持连接”用的是 SSE(Server-Sent Events),本质是一个没有马上结束的 HTTP 请求。 过程是: 拷贝机发送一次请求: GET /api/code-sync/events服务器返回: Content-Type: text/event-stream但不关闭响应&…

2026/8/24 13:42:17

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/24 18:13:48

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/25 1:08:14

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…