news 2026/4/27 9:30:28

【LeetHOT100】删除链表的倒数第 N 个结点——Java多解法详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【LeetHOT100】删除链表的倒数第 N 个结点——Java多解法详解

一、题目描述

19. 删除链表的倒数第 N 个结点

给你一个链表,删除链表的倒数第n个结点,并且返回链表的头结点。

示例 1:

输入:head = [1,2,3,4,5]n = 2
输出:[1,2,3,5]

示例 2:

输入:head = [1]n = 1
输出:[]

示例 3:

输入:head = [1,2]n = 1
输出:[1]

提示:

  • 链表中结点的数目为sz

  • 1 <= sz <= 30

  • 0 <= Node.val <= 100

  • 1 <= n <= sz

进阶:你能尝试使用一趟扫描实现吗?

二、解题思路概览

删除倒数第 N 个结点,核心是找到它的前驱节点。常见解法有三种:

解法时间复杂度空间复杂度特点
两次遍历(计算长度)O(L)O(1)最简单,容易理解
快慢指针(一次遍历)O(L)O(1)面试首选,满足进阶要求
栈辅助O(L)O(L)利用栈的 LIFO 特性

三、解法一:两次遍历(计算链表长度)

3.1 思路

  1. 第一次遍历:计算链表的总长度length

  2. 倒数第n个结点,就是正数第length - n个结点(从 1 开始计数);

  3. 第二次遍历:找到第length - n - 1个结点(前驱),将其next指向下下个结点;

  4. 注意:如果删除的是头结点,需要特殊处理。

3.2 代码实现

java

class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { // 1. 计算链表长度 int length = 0; ListNode p = head; while (p != null) { length++; p = p.next; } // 2. 计算需要删除的节点是正数第几个(从1开始) int targetIndex = length - n + 1; // 3. 处理删除头结点的情况 if (targetIndex == 1) { return head.next; } // 4. 找到要删除节点的前驱 ListNode prev = head; for (int i = 1; i < targetIndex - 1; i++) { prev = prev.next; } // 5. 删除节点 prev.next = prev.next.next; return head; } }

3.3 复杂度分析

  • 时间复杂度:O(L),遍历两次链表。

  • 空间复杂度:O(1),只用了几个指针变量。

四、解法二:快慢指针(一次遍历)⭐

4.1 思路

使用两个指针slowfast,初始化都指向哑结点(dummy node):

  • fast先移动n步;

  • 然后slowfast同时移动,直到fast到达链表末尾;

  • 此时slow.next就是要删除的节点(因为slowfast之间始终相隔n个节点);

  • 删除slow.next即可。

使用哑结点可以避免对头结点的特殊处理,使代码更统一。

4.2 代码实现

java

class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0, head); ListNode slow = dummy; ListNode fast = dummy; // 快指针先走 n 步 for (int i = 0; i < n; i++) { fast = fast.next; } // 同时移动,直到 fast 到达末尾 while (fast.next != null) { slow = slow.next; fast = fast.next; } // 删除 slow.next slow.next = slow.next.next; return dummy.next; } }

4.3 图解示例

head = [1,2,3,4,5]n = 2为例:

text

初始: dummy → 1 → 2 → 3 → 4 → 5 → null slow, fast 都指向 dummy 第1步: fast 先走 n=2 步 dummy → 1 → 2 → 3 → 4 → 5 → null ↑ ↑ slow fast 第2步: 同时移动,直到 fast.next == null dummy → 1 → 2 → 3 → 4 → 5 → null ↑ ↑ slow fast 此时 slow.next 指向节点 4,正是要删除的节点 执行 slow.next = slow.next.next 即可删除节点 4

4.4 复杂度分析

  • 时间复杂度:O(L),只遍历一次链表。

  • 空间复杂度:O(1)。

五、解法三:使用栈

5.1 思路

  1. 遍历链表,将所有节点依次压入栈中;

  2. 从栈顶弹出n个节点(即倒数第n个节点会留在栈顶);

  3. 再弹出一次,得到倒数第n个节点的前一个节点;

  4. 修改指针完成删除。

5.2 代码实现

java

class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(0, head); Deque<ListNode> stack = new ArrayDeque<>(); ListNode p = dummy; // 将链表节点(包括哑结点)全部入栈 while (p != null) { stack.push(p); p = p.next; } // 弹出 n 个节点,此时栈顶就是倒数第 n 个节点的前驱 for (int i = 0; i < n; i++) { stack.pop(); } ListNode prev = stack.peek(); // 前驱节点 prev.next = prev.next.next; // 删除目标节点 return dummy.next; } }

5.3 复杂度分析

  • 时间复杂度:O(L),遍历一次 + 栈操作 O(1) 每次。

  • 空间复杂度:O(L),栈需要存储所有节点。

六、解法对比与总结

方法时间复杂度空间复杂度是否一次遍历推荐度
两次遍历O(L)O(1)⭐⭐⭐
快慢指针O(L)O(1)⭐⭐⭐⭐⭐
O(L)O(L)⭐⭐

6.1 面试建议

  • 首选快慢指针法:一次遍历 + O(1) 空间,完美满足进阶要求,也是面试官最期待的答案。

  • 注意使用哑结点(dummy node)来简化头结点的删除逻辑。

  • 边界条件:n有效(1 ≤ n ≤ sz),题目已保证,无需额外校验。

6.2 常见错误

  1. 忘记处理头结点删除:如果不使用哑结点,需要单独判断targetIndex == 1的情况。

  2. 快慢指针初始位置错误fast先走n步,如果初始都指向head,则删除头结点时会出现空指针异常。使用哑结点可避免。

  3. 快慢指针移动条件:应该是fast.next != null,而不是fast != null,否则slow会多走一步。

七、相关链接

  • 题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

  • 官方题解:删除链表的倒数第 N 个结点官方题解

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

一文快速搞懂I2C测试原理和测试方法

1. I2C概述I2C&#xff08;Inter-Integrated Circuit&#xff09;&#xff0c;中文应该叫集成电路总线&#xff0c;它是一种串行通信总线&#xff0c;使用多主从架构&#xff0c;是由飞利浦公司在1980年代初设计的&#xff0c;方便了主板、嵌入式系统或手机与周边设备组件之间的…

作者头像 李华
网站建设 2026/4/27 9:27:40

【遮天剧场版】《背棺战王腾》

通过百度网盘分享的文件&#xff1a;叶遮天剧场版 链接:https://pan.baidu.com/s/1xN3rWW-Wztmuh6dyaneNcA?pwd72c2 提取码:72c2复制这段内容打开「百度网盘APP 即可获取」 剑来2动画点映超前点播&#xff1a; 我用夸克网盘给你分享了「cqdy」&#xff0c;点击链接或复制整段内…

作者头像 李华
网站建设 2026/4/27 9:20:15

Qianfan-OCR-4B算法原理浅析:从CNN到端到端文档理解

Qianfan-OCR-4B算法原理浅析&#xff1a;从CNN到端到端文档理解 1. 引言&#xff1a;当计算机开始"阅读"文档 想象一下&#xff0c;你面前有一份复杂的商业报告&#xff0c;里面有表格、段落文字、图表和手写批注。人类可以轻松理解这种混合内容&#xff0c;但对计…

作者头像 李华
网站建设 2026/4/27 9:20:14

从Cortex-M到Cortex-A:内存屏障(DMB/DSB/ISB)的使用差异与迁移心得

从Cortex-M到Cortex-A&#xff1a;内存屏障的思维升级与实践指南 当工程师从单片机开发转向Linux驱动或Android系统开发时&#xff0c;往往会遇到一个令人困惑的现象&#xff1a;同样的内存屏障指令&#xff0c;在Cortex-M上运行良好的代码&#xff0c;移植到Cortex-A平台后却出…

作者头像 李华