ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LeetCode 面试题 02.03 删除中间节点:仅凭节点本身完成链表删除的 O(1) 解法(doocs/leetcode 多语言实现全解析)

LeetCode 面试题 02.03 删除中间节点:仅凭节点本身完成链表删除的 O(1) 解法(doocs/leetcode 多语言实现全解析) 示例工程教程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载本文基于 doocs/leetcode 仓库中《程序员面试金典第 6 版》题解目录的 面试题 02.03 删除中间节点 展开。该题要求只给出链表中的一个「中间节点」既不给头节点也不给前驱便将其从链表中删除。读完本文你将掌握经典的「后继节点赋值覆盖」技巧理解为什么该技巧能把删除操作压缩到 O(1) 时间与 O(1) 空间并能在 Python、Java、C、Go、JavaScript、Swift 六种语言中直接落地实现。题目背景与核心约束本题目录位于仓库lcci/LeetCode 程序员面试金典题解集下英文版见 README_EN.md。题目定义如下若链表中的某个节点既不是链表头节点也不是链表尾节点则称其为该链表的「中间节点」。假定已知链表的某一个中间节点请实现一种算法将该节点从链表中删除。例如传入节点c位于单向链表a-b-c-d-e-f中将其删除后剩余链表为a-b-d-e-f。示例输入节点 5 位于单向链表 4-5-1-9 中 输出不返回任何数据从链表中删除传入的节点 5使链表变为 4-1-9这道题有三个容易被忽略、但决定算法走向的硬性约束只给待删除节点本身函数签名不接收头节点head也没有前驱节点prev该节点保证是中间节点不是头节点也不是尾节点因此node.next一定存在且非空不要求返回新链表只需原地修改链表方法返回void。解法核心思想节点赋值Node Assignment为什么不能走常规删除路径常规删除链表中某个节点标准做法是找到它的前驱节点改写前驱的next指针以跳过待删节点。但本题只给出待删节点本身且单向链表无法回溯到前驱因此这条常规路径被彻底堵死。原文档的思考过程点破了关键删除的可见效果是该位置的值与后继关系「消失」。既然无法改动前驱的指针那就换个思路——把后继节点的值复制到当前节点再让当前节点跳过后继从调用者的视角看当前节点所代表的值与后继关系都消失了效果等价于删掉了当前节点。两步赋值即可完成node.val node.next.val // 用后继的值覆盖当前节点的值 node.next node.next.next // 让当前节点跳过后继直接指向后继的后继第一步解决「值消失」第二步解决「后继关系消失」。整个过程不涉及任何头节点或前驱指针时间复杂度 O(1)空间复杂度 O(1)。六语言实现与逐行解析仓库在该目录下为每种语言提供了独立的 Solution 文件与 README.md 中嵌入的代码块一一对应。下面逐语言给出完整实现并说明关键点。Python3# Definition for singly-linked list. # class ListNode: # def __init__(self, x): # self.val x # self.next None class Solution: def deleteNode(self, node): node.val node.next.val node.next node.next.next对应文件Solution.py。Python 动态语言无需显式类型直接对传入节点做两步赋值即可。Java/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val x; } * } */ class Solution { public void deleteNode(ListNode node) { node.val node.next.val; node.next node.next.next; } }对应文件Solution.java。方法签名返回void符合「不返回任何数据」的题目要求。C/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: void deleteNode(ListNode* node) { node-val node-next-val; node-next node-next-next; } };对应文件Solution.cpp。C 中node为指针因此访问成员使用-。Go/** * Definition for singly-linked list. * type ListNode struct { * Val int * Next *ListNode * } */ func deleteNode(node *ListNode) { node.Val node.Next.Val node.Next node.Next.Next }对应文件Solution.go。Go 结构体字段名大写Val、Next与题面给出的ListNode定义保持一致。JavaScript/** * Definition for singly-linked list. * function ListNode(val) { * this.val val; * this.next null; * } */ /** * param {ListNode} node * return {void} Do not return anything, modify node in-place instead. */ var deleteNode function (node) { node.val node.next.val; node.next node.next.next; };对应文件Solution.js。JSDoc 注释明确要求原地修改modify node in-place且不返回任何值。Swift/** * public class ListNode { * var val: Int * var next: ListNode? * init(_ x: Int) { * self.val x * self.next nil * } * } */ class Solution { func deleteNode(_ node: ListNode?) { guard let node node, let next node.next else { return } node.val next.val node.next next.next } }对应文件Solution.swift。Swift 中ListNode.next是可选类型ListNode?因此实现用guard let解包出当前节点与后继节点若next为nil理论上题目保证不会发生则直接返回保证了空安全。复杂度分析指标复杂度说明时间复杂度O(1)仅两次赋值无任何遍历空间复杂度O(1)未申请任何额外数据结构Swift 仅使用解包出的局部引用不占额外渐进空间原文档明确标注时间复杂度 O(1)空间复杂度 O(1)。边界条件与常见误区结合题目约束与各语言实现有几个边界细节值得注意待删节点不能是尾节点算法依赖node.next存在。若node是尾节点node.next为null第一步取值就会空指针异常。题目已保证「既不是头节点也不是尾节点」这正是该解法成立的前提若需要支持删除尾节点必须换用「找前驱 断链」的常规算法。待删节点不能是头节点吗题目只保证「中间节点」但实际算法对头节点同样有效——拷贝后继值、跳过后继后head指向的节点依然存在于链表中只是值变了。不过既然题目只要求删除中间节点实现中无需考虑头节点场景。被跳过的后继节点第二步node.next node.next.next执行后原后继节点不再被链表引用。在无 GC 语言如 C中若由new分配理论上应释放其内存在线评测环境通常不做要求且本题签名不返回该指针无法在方法内安全释放。实现上以题面为准不引入额外内存管理。原文档思考段落还提醒从调用者视角看「该位置的值与后继关系消失」即等价于删除。这意味着若调用方持有指向该节点的引用删除后该引用的值已被替换为后继的值——这是「节点赋值法」与常规删除在语义上的唯一差异。与常规链表删除的对比从同仓库题解看两种套路在lcci/目录下可以横向对比「给头节点删除」与「只给节点删除」两种题型的代码差异这有助于把本题技巧放进完整的链表操作知识体系中常规删除需要前驱指针如 02.01 移除重复节点 的解法遍历时始终维护pre前驱指针用pre.next pre.next.next完成删除同时配合哈希集合判重02.04 分割链表 则维护哑节点dummy node与双指针来重构链表。这类场景下前驱/头节点是删除的必备输入。只给节点删除本题没有前驱可用只能利用「中间节点必有后继」这一保证用拷贝覆盖代替指针重连。更进一步从源码结构可以推断仓库中 面试题 18 删除链表的节点剑指 Offer 版与本题形成天然对照那题同时给出头节点与待删值需要遍历定位前驱本题连头节点都不给考验的正是对链表「值拷贝删除」这一经典技巧的掌握。两题配合练习可以完整覆盖链表的两种删除范式。小结面试题 02.03 的核心考点并非「会写删除」而是考察候选人能否在缺少前驱指针的约束下跳出惯性思维——用「拷贝后继 跳过后继」的 O(1) 技巧完成等价删除。doocs/leetcode 仓库为该题提供了 README 题解 及 Python、Java、C、Go、JavaScript、Swift 六种语言的 Solution 文件实现与文档完全一致可直接对照学习或本地运行验证。掌握这一技巧后遇到「只给节点做链表操作」类题目时你便多了一把 O(1) 空间的利器。赞分享示例工程教程【免费下载链接】leetcodeLeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer第 2 版》、《程序员面试金典第 6 版》题解项目地址https://gitcode.com/doocs/leetcode点击查看免费下载相关推荐Czkawka 磁盘清理工具完整教程一次扫描定位重复文件与空文件夹Czkawka 磁盘清理工具完整教程一次扫描定位重复文件与空文件夹 Czkawka 是一款用 Rust 编写的免费开源磁盘清理工具能把你指定的目录一次性扫一桌面应用链表节点删除的 O(1) 技巧AlgoNote 详解 LeetCode 0237「删除链表中的节点」链表节点删除的 O 1 技巧AlgoNote 详解 LeetCode 0237「删除链表中的节点」 导读 本文围绕「算法通关手册」AlgoNote 仓库中 0教程文档知识库PyTorch-CycleGAN损失函数详解Cycle Consistency如何保证转换质量PyTorch CycleGAN损失函数详解Cycle Consistency如何保证转换质量 CycleGAN是一种强大的无监督图像转换模型它能够在没有上一篇韧性工程实战指南构建抗压系统的四维策略下一篇ManiSkill机器人模拟环境完全实战指南从安装到优化的全方位教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表