【忍者算法】从快慢指针到倒数查找:优雅解决链表倒数问题|LeetCode第19题"删除链表的倒数第N个结点"
从快慢指针到倒数查找:优雅解决链表倒数问题
从生活场景说起
想象你在一个漫长的队伍中,想知道自己距离队尾还有多少人。一个巧妙的方法是:让你的朋友从你所在位置往后数N步,然后你和朋友一起向后走。当朋友走到队尾时,你的位置就正好是倒数第N个。这个生活中的小技巧,正是我们今天要探讨的链表算法的灵感来源。
问题描述
LeetCode第19题"删除链表的倒数第N个结点"要求:给你一个链表的头节点 head 和一个整数 n ,请你删除链表的倒数第 n 个结点,并且返回链表的头结点。
例如:
输入:1 → 2 → 3 → 4 → 5, n = 2
输出:1 → 2 → 3 → 5
解释:删除倒数第2个节点(值为4)
输入:1 → 2, n = 2
输出:2
解释:删除倒数第2个节点(值为1)
输入:1, n = 1
输出:空链表
解释:删除唯一的节点
初步思路:两次遍历法
最直观的解法是先遍历一遍链表得到长度,然后再遍历一次删除目标节点:
public ListNode removeNthFromEnd(ListNode head, int n) {
// 第一次遍历,计算链表长度
int length = 0;
ListNode current = head;
while (current != null) {
length++;
current = current.next;
}
// 如果要删除的是头节点
if (length == n) {
return head.next;
}
// 找到待删除节点的前一个节点
current = head;
for (int i = 0; i < length - n - 1; i++) {
current = current.next;
}
// 执行删除操作
current.next = current.next.next;
return head;
}
优化解法:快慢指针一次遍历
就像我们在队伍中的例子,我们可以用快慢指针在一次遍历内解决问题:
public ListNode removeNthFromEnd(ListNode head, int n) {
// 创建哨兵节点,统一处理头节点的删除
ListNode dummy = new ListNode(0);
dummy.next = head;
// 初始化快慢指针
ListNode fast = dummy;
ListNode slow = dummy;
// 快指针先走n+1步(多走一步是为了让慢指针停在待删除节点的前一个位置)
for (int i = 0; i <= n; i++) {
fast = fast.next;
}
// 快慢指针同步移动
while (fast != null) {
fast = fast.next;
slow = slow.next;
}
// 执行删除操作
slow.next = slow.next.next;
return dummy.next;
}
图解过程
例子:删除倒数第2个节点
1) 初始状态:
dummy → 1 → 2 → 3 → 4 → 5
S,F
2) 快指针先走n+1步:
dummy → 1 → 2 → 3 → 4 → 5
S F
3) 同步移动直到快指针到末尾:
dummy → 1 → 2 → 3 → 4 → 5
S F
4) 删除slow.next节点:
dummy → 1 → 2 → 3 → 5
深入理解快慢指针解法
为什么这个方法能工作?让我们仔细分析:
- 快指针先走n+1步,与慢指针产生n+1的距离
- 当快指针到达末尾(null)时,慢指针正好在待删除节点的前一个位置
- 这保证了我们总能找到待删除节点的前驱节点,便于执行删除操作
复杂度分析
两次遍历法:
- 时间复杂度:O(L),需要两次遍历
- 空间复杂度:O(1)
- 优点:直观易懂
- 缺点:需要两次遍历
快慢指针法:
- 时间复杂度:O(L),只需一次遍历
- 空间复杂度:O(1)
- 优点:一次遍历即可完成,更优雅
- 缺点:需要理解快慢指针的原理
技巧总结
哨兵节点的使用
- 统一了头节点的处理
- 避免了额外的边界检查
快慢指针的设计
- 快指针先走n+1步的巧妙设计
- 同步移动直至快指针到达末尾
边界情况的处理
- 链表长度等于n
- 只有一个节点
- n等于链表长度
实际应用延伸
这种快慢指针的思想在实际开发中有很多应用:
- 缓存淘汰算法
- 流式数据的滑动窗口处理
- 实时数据处理中的延迟计算
小结与思考
通过这个问题,我们学到了:
- 如何用空间换时间(两次遍历)
- 如何用巧妙的算法优化空间(快慢指针)
- 哨兵节点的实用价值
- 如何优雅处理链表的边界情况
当我们遇到类似的"倒数"问题时,可以考虑:
- 是否可以用快慢指针解决?
- 是否需要哨兵节点简化处理?
- 如何在一次遍历中完成任务?
记住:有时看似复杂的问题,用合适的思维方式就能找到优雅的解决方案。
作者:忍者算法
公众号:忍者算法
我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~
【忍者算法】从快慢指针到倒数查找:优雅解决链表倒数问题|LeetCode第19题"删除链表的倒数第N个结点"的更多相关文章
- Leetcode(19)-删除链表的倒数第N个节点
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. 示例: 给定一个链表: 1->2->3->4->5, 和 n = 2. 当删除了倒数第二个节点后,链表变为 ...
- LeetCode第[19]题(Java):Remove Nth Node From End of List(删除链表的倒数第N个节点)
题目:删除链表的倒数第N个节点 难度:Medium 题目内容: Given a linked list, remove the n-th node from the end of list and r ...
- 【LeetCode题解】19_删除链表的倒数第N个节点(Remove-Nth-Node-From-End-of-List)
目录 描述 解法:双指针 思路 Java 实现 Python 实现 复杂度分析 更多 LeetCode 题解笔记可以访问我的 github. 描述 给定一个链表,删除链表的倒数第 n 个节点,并且返回 ...
- LeetCode 19:删除链表的倒数第N个节点 Remove Nth Node From End of List
给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点. Given a linked list, remove the n-th node from the end of list and ...
- 【LeetCode 19】删除链表的倒数第N个节点
题目链接 [题解] 经典的一道题. 让p1指向链表的第一个元素. 让p2指向链表的第二个元素. 然后让他们俩同时往后移动. 直到p2到达链表的尾巴. 这时p1和p2之间总是隔了n-1个元素. 所以p1 ...
- 19。删除链表倒数第N个节点
class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next# 这道题还是很简单的,我们只 ...
- 【LeetCode】19. Remove Nth Node From End of List 删除链表的倒数第 N 个结点
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:链表, 删除节点,双指针,题解,leetcode, 力扣 ...
- Leetcode算法系列(链表)之删除链表倒数第N个节点
Leetcode算法系列(链表)之删除链表倒数第N个节点 难度:中等给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点.示例:给定一个链表: 1->2->3->4-&g ...
- 打败算法 —— 删除链表的倒数第n个结点
本文参考 出自LeetCode上的题库 -- 删除链表的倒数第n个结点,官方的双指针解法没有完全符合"只遍历一遍链表"的要求,本文给出另一种双指针解法 https://leetco ...
- 【算法训练营day4】LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表II
[算法训练营day4]LeetCode24. 两两交换链表中的结点 LeetCode19. 删除链表的倒数第N个结点 LeetCode面试题 02.07. 链表相交 LeetCode142. 环形链表 ...
随机推荐
- docker-compose的nginx更换完ssl证书不起作用的完美解决方法
以Harbor为例,ssl证书更新后,docker-compose启动不起作用. 问题出在一句很重要的命令:./prepare 步骤:(Harbor样例) 1. cd /data/ssl 换ssl证 ...
- 【Amadeus原创】HP惠普笔记本重装系统无法引导无法进操作系统的终极解决方法
F9进入BIOS-先进(Advanced)-安全引导配置- 启用传统支持和禁用安全引导
- LocalLLaMA 客户端试验
LM Studio. 可以直接下 hg 模型(实际使用需要自己修改成中国镜像). 有 local server, 符合 openai api 规范. 遗憾的是不支持选择显卡导致无法使用. Farada ...
- [Mybatis Plus]lambdaQueryWrapper和QueryWrapper的选择
结论 更推荐使用:LambdaQueryWrapper QueryWrapper:灵活但是不够类型安全 LambdaQueryWrapper:安全 分析 在MyBatis-Plus中,QueryWra ...
- Qt编写安防视频监控系统42-用户权限
一.前言 前几年写这个视频监控系统的时候,就规划过要加入用户权限管理,因为不属于急需要的功能一直耽搁至今,近期刚好其他几个项目要需要这个功能,和秘钥认证一样,于是一鼓作气就把这几个功能一块干掉,本次完 ...
- 模拟数据生成器mock.js入门
1.在某一指定目录下,按下shift+鼠标右键,,点击"在此处打开Powershell窗口(S)",启动命令行窗口.如下图: 2.在窗口中输入以下命令以便创建项目:vue crea ...
- 基于开源IM即时通讯框架MobileIMSDK:RainbowChat v8.3版已发布
关于MobileIMSDK MobileIMSDK 是一套专门为移动端开发的开源IM即时通讯框架,超轻量级.高度提炼,一套API优雅支持UDP .TCP .WebSocket 三种协议,支持iOS.A ...
- SpringBoot原理深入及源码剖析(二) 自定义Starter及SpringBoot执行原理
自定义Starter SpringBoot starter机制 SpringBoot由众多starter组成(一系列的自动化配置的starter插件),SpringBoot之所以流行,也是因为star ...
- DEAT NOTE
动漫 评分/10 评价 进击的巨人 10 献出心脏! Re:从零开始的异世界生活 10 蕾姆蕾姆!!! 反叛的鲁鲁修 10 算无遗策鲁鲁修 末日时在做什么?... 9 谁还不是个珂学家 东京食尸鬼 9 ...
- python创建项目虚拟环境
创建一个文件夹用于存放你的虚拟环境 cd 到存放虚拟环境的地址 安装虚拟环境库: pip3 install virtualenv 创建虚拟环境:python3 -m venv 环境名称 激活虚拟环境: ...