跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

链表算法专题:常用技巧与经典题目解析

链表算法的常用技巧及六道经典题目。技巧包括画图、虚拟头节点、快慢双指针等。题目涵盖两数相加、两两交换节点、重排链表、合并 K 个升序链表及 K 个一组翻转链表。每道题均提供了思路解析与 C++ 代码实现,重点讲解边界处理与内存管理。

DevStack发布于 2026/3/30更新于 2026/9/576 浏览
链表算法专题:常用技巧与经典题目解析

1、链表类算法题常用技巧

【技巧】

  1. 画图:直观 + 形象 + 便于理解。
  2. 引入虚拟头节点:链表类型算法题通常是不带头节点的单向链表,从第一个位置开始存储有效数据。引入不存储数据的哨兵节点,便于处理边界情况,方便操作。
  3. 大胆定义变量:直接定义指针保存节点,避免担心语句执行顺序导致丢失。
  4. 快慢双指针:适用于判断链表是否有环、找环入口、找倒数第 n 个节点。

【链表中的常用操作】

  1. 创建一个新节点 new。
  2. 尾插:先定义变量指向尾节点,tail->next = 新节点,tail 指向新节点(初始化时尾指针指向最后一个节点)。
  3. 头插:使用虚拟头节点,让新节点的 next 指向虚拟头节点的 next,然后让虚拟头节点的 next 指向新节点。头插法可直接用于逆序链表。

*只需定义一个 cur,再完成头插即可实现逆序链表。

【注意】链表题一定要特别注意空节点!*

2、2.两数相加

文章配图

题目解析:

输入为逆序存储的链表数字,例如 342+465=807,返回 708。逆序存储方便从最低位开始相加,对应链表的低位节点。

思路:

先创建虚拟头节点 newhead,初始化 t 用来存储两数加的结果。将 cur1 和 cur2 的值累加到 t 中,求出 t 的个位,创建新节点放入结果链表尾部。

文章配图

/** * 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) { ListNode* cur1 = l1, *cur2 = l2; ListNode* newhead = new ListNode(0); // 创建虚拟头节点 ListNode* prev = newhead; // 尾指针 int t = 0; // 记录进位 while(cur1 || cur2 || t) { if(cur1) { t += cur1->val; cur1 = cur1->next; } if(cur2) { t += cur2->val; cur2 = cur2 -> next; } prev->next = new ListNode(t % 10); prev = prev->next; t /= 10; } prev = newhead->next; delete newhead; return prev; } };

3、24.两两交换链表中的节点

文章配图 文章配图 文章配图

/** * 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* swapPairs(ListNode* head) { if(head == nullptr || head->next == nullptr) return head; ListNode* newhead = new ListNode(0); newhead->next = head; ListNode* prev = newhead, *cur = prev->next, *next = cur->next, *nnext = next->next; while(cur && next) { prev->next = next; cur->next = nnext; next->next = cur; prev = cur; cur = nnext; if(cur) next = cur->next; if(next) nnext = next->next; } cur = newhead->next; delete newhead; return cur; } };

4、143.重排链表

文章配图

题意: 输出第一个,倒数第一个,第二个,倒数第二个这样输出。

算法思想: 模拟。

  1. 找到链表的中间节点(使用快慢指针)。
  2. 把后面的部分逆序(头插法)。
  3. 合并两个链表(使用双指针)。

分类讨论: 当链表元素有奇数个时,slow 指针刚好指向中间;偶数个时,slow 指向中间偏右。对后半部分链表进行反转操作,包含 slow 所指向的节点一起反转均适用。若拆分链表需注意断开连接,建议加虚拟头节点。

步骤:

  • 第二步:反转(头插 + 虚拟头节点)。
  • 第三步:合并(尾插 + 虚拟头节点 + 尾指针)。
/** * 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: void reorderList(ListNode* head) { if(head == nullptr || head->next == nullptr || head->next->next == nullptr) return; ListNode* slow = head, *fast = head; while(fast && fast->next) { slow = slow->next; fast = fast->next->next; } ListNode* head2 = new ListNode(0); ListNode* cur = slow->next; slow->next = nullptr; while(cur) { ListNode* next = cur->next; cur->next = head2->next; head2->next = cur; cur = next; } ListNode* ret = new ListNode(0); ListNode* prev = ret; ListNode* cur1 = head, *cur2 = head2->next; while(cur1) { prev->next = cur1; cur1 = cur1->next; prev = prev->next; if(cur2) { prev->next = cur2; cur2 = cur2->next; prev = prev->next; } } delete head2; delete ret; } };

5、23.合并 K 个升序链表

文章配图

利用优先级队列: 创建一个小根堆,使用 k 个指针,先指向第一个节点,把这些元素全放进小根堆当中。拿出堆顶的元素,如果这个节点的后面还有节点就放到堆里。

/** * 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 { struct cmp { bool operator()(const ListNode* l1, const ListNode* l2) { return l1->val > l2->val; } }; public: ListNode* mergeKLists(vector<ListNode*>& lists) { priority_queue<ListNode*,vector<ListNode*>, cmp> heap; for(auto l : lists) if(l) heap.push(l); ListNode* ret = new ListNode(0); ListNode* prev = ret; while(!heap.empty()) { ListNode* t = heap.top(); heap.pop(); prev->next = t; prev = t; if(t->next) heap.push(t->next); } prev = ret->next; delete ret; return prev; } };

6、25.K 个一组翻转链表

文章配图

思路:

  1. 先求出需要逆序多少组:n = 长度/k。
  2. 重复 n 次,长度为 k 的链表的逆序(链表逆序用头插法)。
  3. 注意:当反转完一组之后,进入下一组的时候,不能把下一组的元素放到上一组的前面。进入每组的反转循环时,先记录一下第一个节点,当这组反转完之后,把下组放在这个节点的后面开始头插。
/** * 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* reverseKGroup(ListNode* head, int k) { int n = 0; ListNode* cur = head; while(cur) { cur = cur->next; n++; } n /= k; ListNode* newhead = new ListNode(0); ListNode* prev = newhead; cur = head; for(int i = 0; i < n; i++) { ListNode* tmp = cur; for(int j = 0; j < k; j++) { ListNode* next = cur->next; cur->next = prev->next; prev->next = cur; cur = next; } prev = tmp; } prev->next = cur; cur = newhead->next; delete newhead; return cur; } };

目录

  1. 1、链表类算法题常用技巧
  2. 2、2.两数相加
  3. 3、24.两两交换链表中的节点
  4. 4、143.重排链表
  5. 5、23.合并 K 个升序链表
  6. 6、25.K 个一组翻转链表

更多推荐文章

查看全部
  • Android Framework 核心源码解析指南
  • 深度学习模型优化策略与实战调参
  • 伊凡·苏泽兰:计算机图形学与虚拟现实的奠基人
  • Python 数据分析与 Spark、Hive 对比
  • 基于 OrangePi-5 Plus/Ultra 与 YOLO26n 实现高性能无人机检测
  • 自然语言处理在社交媒体分析中的应用与实战
  • 开源 AI 联网搜索工具 OpenWebSearch MCP 支持多引擎与流式响应
  • Git Clone 命令详解
  • Amazon SageMaker 部署 AIGC 应用:训练、优化与 Web 前端集成
  • ROS1 机器人 SLAM:Gmapping 算法详解与实战
  • OpenClaw:AI 代理工具的贾维斯时刻与开源发展历程
  • MCP 协议详解:与 Function Call 的区别及实战使用
  • Neo4j Desktop 2 安装与实战指南
  • Stack-Chan 机器人快速入门指南
  • PyArrow:Apache Arrow 的 Python 绑定与高效数据交换
  • LLM 与 AIGC 融合:编程范式的转变与实践案例
  • Claude Code 规则配置指南与最佳实践
  • RAG 技术深度解析
  • OpenClaw 本地 AI 助手钉钉对接部署教程
  • AI 产品经理必备的 AI 技术知识

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online