news 2026/5/25 18:25:50

LeetCode 83/237/82 链表删除问题-盒子模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode 83/237/82 链表删除问题-盒子模型

目录

一、LeetCode 83 移除排序链表中的重复元素(保留一个)

题目核心

核心难点拆解

深度思路(盒子 - 标签 - 纸条模型)

代码实现

易踩坑点 & 底层原理

二、LeetCode 237 删除链表中的节点(无法访问头节点)

题目核心

核心难点拆解

深度思路(盒子 - 标签 - 纸条模型)

代码实现

易踩坑点 & 底层原理

三、LeetCode 82 删除排序链表中的重复元素 II(全删)

题目核心

核心难点拆解

深度思路(盒子 - 标签 - 纸条模型)

代码实现

易踩坑点 & 底层原理

四、跨题深度对比:链表删除的底层逻辑

通用核心原则(所有链表删除题的底层逻辑)

进阶思考


一、LeetCode 83 移除排序链表中的重复元素(保留一个)

题目核心

已排序链表中,重复元素仅保留一个(如1→1→1→2→3→31→2→3)。

核心难点拆解

  1. 为什么不能直接比较curcur.next若让cur初始指向head,比较cur.val == cur.next.val,会导致:
    • 空指针风险:当链表只剩最后一个节点时,cur.nextnull
    • 锚点丢失:cur移动后无法回溯,连续重复节点删不干净(如1→1→1会剩最后一个 1,但中间的重复删不彻底)。
  2. dummy哑节点的底层价值:并非仅为 “避免删头节点”,而是提供一个永远非空的 “根锚点”,让cur可以稳定锚定 “已保留的最后一个不重复节点的前驱”,避免遍历过程中链表断裂。

深度思路(盒子 - 标签 - 纸条模型)

模型元素角色与逻辑
盒子链表节点实体(如 1、1、2),排序特性保证 “重复节点必连续”,无需跨区间检查;
标签-dummy:贴在虚拟盒子(val=0)上,永久锚点,不移动;-cur:贴在 “已保留最后一个不重复节点的前驱盒子”(初始贴dummy),仅在无重复时后移;
纸条删除的本质是修改cur.next(纸条指向),跳过重复盒子;连续重复时cur不移动,持续修改纸条直到无重复。

代码实现

class Solution { public ListNode deleteDuplicates(ListNode head) { // 关键点1:空链表防御(基础边界,所有链表题必加) if (head == null) return null; // 关键点2:dummy哑节点——根锚点,避免头节点重复时的边界问题 ListNode dummy = new ListNode(0, head); ListNode cur = dummy; // cur锚定“已保留节点的前驱”,核心标签 // 关键点3:循环条件双层防御——避免cur.next或cur.next.next为null时的空指针 while (cur.next != null && cur.next.next != null) { if (cur.next.val == cur.next.next.val) { // 难点1:连续重复时,cur不移动,仅修改纸条跳过重复节点 // 例:1→1→1,第一次跳过第二个1,cur仍在dummy,第二次跳过第三个1 cur.next = cur.next.next; } else { // 无重复时,cur才后移——保证cur始终锚定“有效前驱” cur = cur.next; } } // 关键点4:返回dummy.next而非head——head可能已被跳过(如链表全重复时) return dummy.next; } }

易踩坑点 & 底层原理

  • 坑 1:循环条件只写cur.next != null→ 会访问cur.next.next导致空指针;
  • 坑 2:连续重复时移动cur→ 如1→1→1,cur 移到第一个 1 后,后续重复节点无法被跳过;
  • 原理:排序链表的重复是 “连续的”,因此只需 “原地跳过”,无需额外存储 / 回溯。

二、LeetCode 237 删除链表中的节点(无法访问头节点)

题目核心

仅给定待删除节点node(非尾节点),无链表头节点访问权限,要求删除该节点(如4→5→1→9删 5 →4→1→9)。

核心难点拆解

  1. 为什么不能直接删除node节点?链表的节点删除本质是 “修改前驱节点的next”,但本题无表头,无法找到node的前驱节点;且链表节点是 “引用类型”,直接置空node仅会让当前标签失效,链表结构未变。
  2. “偷梁换柱” 的底层逻辑:链表的 “节点价值” 在于valnext,而非节点本身的内存地址 —— 因此可以复用node的内存空间,替换其内容为下一个节点的内容,再删除下一个节点,等价于 “逻辑删除node”。
  3. 为什么题目限定 “非尾节点”?node是尾节点,node.nextnull,无法复制内容,此方法失效(尾节点删除必须依赖前驱节点)。

深度思路(盒子 - 标签 - 纸条模型)

模型元素角色与逻辑
盒子待删除盒子(如 5)、下一个盒子(如 1);复用待删除盒子的 “物理空间”,替换其 “内容”;
标签仅能访问node标签(贴在待删除盒子上),无其他锚点标签;
纸条先复制下一个盒子的val到当前盒子,再修改当前盒子的纸条(node.next),跳过下一个盒子;

代码实现

class Solution { public void deleteNode(ListNode node) { // 关键点1:复制下一个盒子的内容到当前盒子——核心逻辑,偷梁换柱 // 例:node是5,node.next是1 → node.val = 1,此时链表变为4→1→1→9 node.val = node.next.val; // 关键点2:修改纸条,跳过下一个盒子——删除“被复制的下一个盒子” // 例:node.next = 1.next = 9,最终链表4→1→9,等价于删除了原5节点 node.next = node.next.next; } }

易踩坑点 & 底层原理

  • 坑 1:试图直接node = null→ 仅让当前标签失效,链表结构无变化(4→5→1→9 仍存在);
  • 坑 2:忽略 “非尾节点” 限制 → 若 node 是尾节点,node.next.val会空指针;
  • 原理:链表的 “节点标识” 是逻辑上的(val+next),而非物理上的(内存地址),这是 “偷梁换柱” 能成立的核心。

三、LeetCode 82 删除排序链表中的重复元素 II(全删)

题目核心

已排序链表中,所有重复出现的元素全部删除,仅保留无重复的元素(如1→2→3→3→4→4→51→2→51→1→1→2→32→3)。

核心难点拆解

  1. 与 83 题的核心差异:83 题是 “保留一个重复元素”,只需 “逐个跳过”;82 题是 “全删重复元素”,需 “定位重复区间的首尾,批量跳过整个区间”。
  2. 为什么需要temp标签遍历重复区间?若仅用cur单次比较cur.nextcur.next.next,无法处理 “超过 2 个的连续重复”(如1→1→1),必须用temp走到重复区间的最后一个节点,才能精准跳过整个区间。
  3. 循环条件的多层防御cur.next != null && cur.next.next != null是 “基础防御”,temp != null && temp.next != null是 “区间遍历防御”,缺一不可 —— 否则会在重复区间末尾访问null.next导致空指针。

深度思路(盒子 - 标签 - 纸条模型)

模型元素角色与逻辑
盒子重复区间内的所有盒子需 “批量跳过”,无重复的盒子需保留;
标签-dummy:永久根锚点;-cur:贴在 “待判断区间的前驱盒子”(初始贴dummy),仅在无重复时后移;-temp:遍历重复区间的临时标签,找到区间末尾;
纸条cur.next直接指向重复区间的下一个盒子,批量删除整个区间的盒子;

代码实现

class Solution { public ListNode deleteDuplicates(ListNode head) { // 关键点1:双层边界防御——空链表/单节点链表直接返回 if (head == null || head.next == null) return head; // 关键点2:dummy哑节点——避免头节点全重复时的边界问题(如1→1→2) ListNode dummy = new ListNode(0, head); ListNode cur = dummy; // cur锚定“待判断区间的前驱” while (cur.next != null && cur.next.next != null) { // 发现重复区间的起点 if (cur.next.val == cur.next.next.val) { // 关键点3:temp标签遍历重复区间,找到区间最后一个节点 ListNode temp = cur.next; // 区间遍历防御:temp != null 避免temp.next空指针 while (temp != null && temp.next != null && temp.val == temp.next.val) { temp = temp.next; // 走到重复区间的最后一个节点 } // 关键点4:批量跳过整个重复区间——核心逻辑 // 例:1→1→1→2,temp走到第三个1,cur.next = 2,直接跳过所有1 cur.next = temp.next; } else { // 无重复时,cur才后移——保证cur始终锚定“有效前驱” cur = cur.next; } } return dummy.next; } }

易踩坑点 & 底层原理

  • 坑 1:temp循环条件漏写temp != null→ 重复区间末尾temp.next为 null,temp.val空指针;
  • 坑 2:找到重复区间后直接cur.next = cur.next.next→ 仅跳过一个重复节点,无法处理多重复(如 1→1→1 仍会剩一个 1);
  • 原理:排序链表的重复区间是 “连续的”,因此只需一次遍历找到区间末尾,即可批量删除,时间复杂度仍为 O (n)。

四、跨题深度对比:链表删除的底层逻辑

维度83 题(重复留一)237 题(指定节点删除)82 题(重复全删)
核心策略逐个跳过重复节点偷梁换柱(内容替换)批量跳过重复区间
锚点依赖依赖 dummy 做根锚点无锚点(仅目标节点)依赖 dummy 做根锚点
空指针防御双层循环条件无(题目限定非尾节点)双层循环 + 区间遍历防御
核心难点连续重复时 cur 不移动理解 “节点逻辑删除”定位重复区间的首尾
底层原理排序链表的连续性链表节点的引用特性排序链表的区间连续性

通用核心原则(所有链表删除题的底层逻辑)

  1. 锚点优先:只要涉及 “删除头节点” 或 “前驱节点不可知”,优先用dummy哑节点做根锚点,避免链表断裂;
  2. 标签不碰原始锚点:始终用cur/temp等临时标签移动,dummy/head等原始锚点仅做初始定位;
  3. 删除本质是改纸条:所有删除操作均不销毁节点(物理删除),而是修改next指向(逻辑删除);
  4. 边界防御前置:所有链表题先处理 “空链表 / 单节点链表”,避免后续循环的空指针。

进阶思考(深度延伸)

  • 若链表未排序,83/82 题该如何修改?→ 需要用哈希表记录已出现的 val,遍历链表时跳过重复值(时间 O (n),空间 O (n));
  • 237 题若允许删除尾节点,该如何处理?→ 必须遍历链表找到尾节点的前驱(时间 O (n)),或改用双向链表(空间换时间)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/18 18:48:39

Nanonets-OCR2 1.5B:文档智能转换的终极解决方案

Nanonets-OCR2 1.5B:文档智能转换的终极解决方案 【免费下载链接】Nanonets-OCR2-1.5B-exp 项目地址: https://ai.gitcode.com/hf_mirrors/nanonets/Nanonets-OCR2-1.5B-exp Nanonets-OCR2 1.5B-exp 是一个革命性的图像转文本OCR模型,能够将复杂…

作者头像 李华
网站建设 2026/5/12 11:13:26

基于RetinaNet和RegNetX-3.2GF的金属焊接缺陷检测与识别实践_1

1. 基于RetinaNet和RegNetX-3.2GF的金属焊接缺陷检测与识别实践 焊接作为现代工业制造中的关键连接技术,在航空航天、汽车制造、能源管道、建筑工程等领域具有广泛应用。焊接质量直接关系到结构的安全性和可靠性,而焊接缺陷的存在会显著降低焊接接头的力…

作者头像 李华
网站建设 2026/5/12 7:43:15

大规模微服务下的 JVM 调优实战指南

文章目录大规模微服务下的 JVM 调优实战指南实例数 vs 内存模型、GC集群权衡与分布式架构影响📋 目录🏗️ 一、大规模微服务的JVM新挑战💡 大规模微服务特有挑战🎯 集群级JVM管理框架⚖️ 二、实例数与内存模型的精妙平衡&#x1…

作者头像 李华
网站建设 2026/5/24 20:34:16

5个实战技巧:用HandyControl打造专业级WPF聊天界面

5个实战技巧:用HandyControl打造专业级WPF聊天界面 【免费下载链接】HandyControl Contains some simple and commonly used WPF controls 项目地址: https://gitcode.com/gh_mirrors/ha/HandyControl 还在为WPF聊天应用开发中的界面卡顿、消息同步困难、样式…

作者头像 李华
网站建设 2026/5/10 21:33:15

DevUI框架中Form表单组件使用详解

&#x1f4cb; 一、组件概述与核心构成 DevUI 的表单组件 (dForm) 是一套用于数据收集、校验和提交的完整解决方案。基于Angular 18.0.0框架&#xff0c;涵盖了从基本结构到高级验证的完整内容。它结构清晰&#xff0c;通常由以下几个核心部分嵌套构成&#xff1a;<form dFo…

作者头像 李华
网站建设 2026/5/21 6:07:59

关于WANCE_SG系列光栅和安全继电器的原理解析

接收端ossd和aux的不同1. OSSD&#xff08;安全输出&#xff09;设计目标&#xff1a;实现最快的安全停机。这是保护人身安全的生命线&#xff0c;其唯一任务就是在检测到危险&#xff08;光束被遮挡&#xff09;时&#xff0c;以最快的速度切断下游的安全电路&#xff0c;从而…

作者头像 李华