LeetCode-Book 精讲:237. 删除链表中的节点——仅凭当前节点指针实现 O(1) 删除的「值替换」技法
2026/9/16 11:22:38 网站建设 项目流程

LeetCode-Book 精讲:237. 删除链表中的节点——仅凭当前节点指针实现 O(1) 删除的「值替换」技法

【免费下载链接】LeetCode-Book《剑指 Offer》《图解算法数据结构》《Krahets 笔面试精选 88 题》Python, Java, C++ 解题代码项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

导读

本文围绕 LeetCode 237「删除链表中的节点」展开,这是 LeetCode-Book 仓库《Krahets 笔面试精选 88 题》中的一道高频链表基础题。题目最大的陷阱在于:函数只传入「待删除节点」本身,而不给链表头节点,导致常规的「通过前驱节点改指针」方案完全失效。读完本文,你将掌握**「复制后继节点值 + 删除后继节点」**这一 O(1) 时间的核心技法,理解其适用前提与边界限制,并对照本仓库 Python / Java / C++ 三语实现与 C++ 测试用例,彻底吃透这道经典题。

题目本质:只给「节点」,不给「链表」

LeetCode 237 的题目约束决定了它与常规删除操作截然不同:

  • 链表是单向链表,每个节点只有指向后继的next指针;
  • 函数签名只接收待删除节点node本身,不提供头节点head,也不返回任何值;
  • 题目保证传入的节点不是链表尾节点

常规删除需要「前驱指针」,而单向链表无法从当前节点回溯到前驱——这正是本题的难点与考察点。

常规删除为什么行不通

设前驱节点为pre、当前节点为cur、后继节点为cur.next,常规删除的本质是执行一行指针操作:

pre.next = cur.next

即将当前节点从链表中「摘除」。但本题只有node的引用,无法访问node的前驱pre,因此这一常规方法被直接封死。这也是为什么该题被选入精选 88 题——它考察的是对「节点引用」与「链表结构」两者关系的理解深度。

核心思路:「值替换」——复制后继,删除后继

无法动前驱指针,那就换一个思路:不删除传入的node本身,而是让node变成后继节点的“替身”,再把后继节点删掉。具体两步:

  1. 复制后继节点值:把node.next的值赋给node,使node在值上“变成”后继节点;
  2. 逻辑删除后继:执行node.next = node.next.next,把原来的后继节点从链表中摘除。

从最终链表结构看,node这个位置上的值已被替换,后继被跳过,效果等同于「删除了传入节点」。

示例推演:4 → 5 → 1 → 9 中删除节点 5

以文档中的示例链表4 → 5 → 1 → 9、待删除节点为5为例,逐步推演:

步骤操作链表状态
初始4 →5→ 1 → 9
第一步node.val = node.next.val(5 变成 1)4 →1→ 1 → 9
第二步node.next = node.next.next(跳过第二个 1)4 →1→ 9

最终链表变为4 → 1 → 9,数值序列与直接删除节点 5 完全一致。注意:这里被真正“摘除”的是原值 1 所在的后继节点,而传入的node节点对象本身仍留在链表中,只是它的值被覆盖了。删除的是“值”,而不是“指针所指向的节点对象”——这是理解本题的关键。

三语代码实现与注释解析

文档给出了 Python / Java / C++ 三种语言的解法,并在后三个 Tab 中附带了逐行注释版本。以下完整继承并给出带注释的版本:

class Solution: def deleteNode(self, node): # 1. 复制 node.next 的值到 node(“值替换”) node.val = node.next.val # 2. 从链表中删除 node.next(跳过原后继节点) node.next = node.next.next
class Solution { public void deleteNode(ListNode node) { // 1. 复制 node.next 到 node node.val = node.next.val; // 2. 从链表中删除 node.next node.next = node.next.next; } }
class Solution { public: void deleteNode(ListNode* node) { // 1. 复制 node.next 到 node node->val = node->next->val; // 2. 从链表中删除 node.next node->next = node->next->next; } };

三种语言逻辑完全一致,差异仅在于语法:C++ 通过->访问指针成员,Java / Python 通过.访问对象成员。该解法在 LeetCode-Book 仓库中均有对应源码文件:

  • Python:lc_237_delete_node_in_a_linked_list_s1.py 与带注释的 lc_237_delete_node_in_a_linked_list_s2.py;
  • C++:lc_237_delete_node_in_a_linked_list_s1.cpp 与带注释的 lc_237_delete_node_in_a_linked_list_s2.cpp;
  • Java:lc_237_delete_node_in_linked_list_s1.java 与 lc_237_delete_node_in_linked_list_s2.java。

仓库源码佐证:工具函数与 C++ 测试用例

仓库不仅提供解法,还给出了可运行的验证环境,可从源码层面印证上述推理。

链表节点定义与工具函数

Python 侧的工具函数集中在 linked_list.py,核心定义如下:

  • ListNode:单链表节点类,含valnext两个属性;
  • list_to_linked_list(arr):由数组构造链表;
  • linked_list_to_list(head):将链表序列化为数组,便于打印验证;
  • get_list_node(head, val):按值定位节点——这正是本题“只拿到节点、拿不到前驱”场景的模拟入口。

C++ 测试用例:完整验证删除效果

C++ 源码 lc_237_delete_node_in_a_linked_list_s1.cpp 中给出了可运行测试,与文档示例完全对应:

int main() { // ======= Test Case ======= ListNode* head = vectorToLinkedList({4, 5, 1, 9}); ListNode* node = getListNode(head, 5); // ====== Driver Code ====== Solution* slt = new Solution(); slt->deleteNode(node); PrintUtil::printLinkedList(head); return 0; }

执行流程:用数组{4, 5, 1, 9}构造链表 → 按值5定位到待删除节点 → 调用deleteNode(node)→ 打印整个链表。预期输出为4 -> 1 -> 9,与文档推演结果一致,可作为该算法的自动化验证手段。可见仓库源码、文档与题目三者互为印证:删除后传入的node节点仍留在链表中,但链表的数值序列已等价于删除了该节点。

复杂度分析

  • 时间复杂度 O(1):无论链表多长,都只执行两次指针/赋值操作,不涉及遍历,使用常数时间;
  • 空间复杂度 O(1):仅使用常数大小的额外空间,未借助任何辅助容器。

这也是该题“最优解”的复杂度上界——因为题目只给节点引用,任何需要定位前驱的方案都至少是 O(n),而值替换法恰好绕开了这一瓶颈。

边界条件与易错点

  1. 尾节点不可删除:若node是链表尾节点,则node.next为空,代码会因空指针访问崩溃。本题题目约束已保证传入节点不是尾节点,因此可直接使用;但在改写为通用函数时必须显式处理尾节点(如返回None或报错)。
  2. 删除的是“值”而非“对象”:函数执行后,原node节点对象仍在内存中,只是值被覆盖。调用方若持有其他指向原后继节点的引用,会观察到该节点已“脱离”链表。
  3. C++ 内存管理:C++ 版本执行node->next = node->next->next后,被摘除的节点在 LeetCode 评测环境中由平台统一回收;若在本地自行管理内存,需注意避免内存泄漏,考虑手动释放被跳过的后继节点(并同步更新node->next指向)。

小结

「删除链表中的节点」表面是 O(1) 的简单题,实则考察三点:对单链表“只能单向访问”结构的认知、对“删除操作本质是改指针”的抽象能力,以及临场绕开约束的变通思维。值替换法(复制后继值 + 删除后继)是这道题的标准最优解:时间 O(1)、空间 O(1),且三行代码即可实现。掌握这一技法后,建议结合仓库内 LeetCode-Book 精选题解文档 中其他链表题目(如 206. 反转链表、876. 链表的中间结点)继续巩固链表指针操作的基本功。

【免费下载链接】LeetCode-Book《剑指 Offer》《图解算法数据结构》《Krahets 笔面试精选 88 题》Python, Java, C++ 解题代码项目地址: https://gitcode.com/GitHub_Trending/le/LeetCode-Book

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询