【忍者算法】从快慢指针到倒数查找:优雅解决链表倒数问题|LeetCode第19题删除链表的倒数第N个结点

news/2025/2/26 23:31:15/文章来源:https://www.cnblogs.com/renzhesuanfa/p/18740031

从快慢指针到倒数查找:优雅解决链表倒数问题

从生活场景说起

想象你在一个漫长的队伍中,想知道自己距离队尾还有多少人。一个巧妙的方法是:让你的朋友从你所在位置往后数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,F2) 快指针先走n+1步:
dummy → 1 → 2 → 3 → 4 → 5
S           F3) 同步移动直到快指针到末尾:
dummy → 1 → 2 → 3 → 4 → 5S           F4) 删除slow.next节点:
dummy → 1 → 2 → 3 → 5

深入理解快慢指针解法

为什么这个方法能工作?让我们仔细分析:

  1. 快指针先走n+1步,与慢指针产生n+1的距离
  2. 当快指针到达末尾(null)时,慢指针正好在待删除节点的前一个位置
  3. 这保证了我们总能找到待删除节点的前驱节点,便于执行删除操作

复杂度分析

两次遍历法:

  • 时间复杂度:O(L),需要两次遍历
  • 空间复杂度:O(1)
  • 优点:直观易懂
  • 缺点:需要两次遍历

快慢指针法:

  • 时间复杂度:O(L),只需一次遍历
  • 空间复杂度:O(1)
  • 优点:一次遍历即可完成,更优雅
  • 缺点:需要理解快慢指针的原理

技巧总结

  1. 哨兵节点的使用

    • 统一了头节点的处理
    • 避免了额外的边界检查
  2. 快慢指针的设计

    • 快指针先走n+1步的巧妙设计
    • 同步移动直至快指针到达末尾
  3. 边界情况的处理

    • 链表长度等于n
    • 只有一个节点
    • n等于链表长度

实际应用延伸

这种快慢指针的思想在实际开发中有很多应用:

  1. 缓存淘汰算法
  2. 流式数据的滑动窗口处理
  3. 实时数据处理中的延迟计算

小结与思考

通过这个问题,我们学到了:

  1. 如何用空间换时间(两次遍历)
  2. 如何用巧妙的算法优化空间(快慢指针)
  3. 哨兵节点的实用价值
  4. 如何优雅处理链表的边界情况

当我们遇到类似的"倒数"问题时,可以考虑:

  1. 是否可以用快慢指针解决?
  2. 是否需要哨兵节点简化处理?
  3. 如何在一次遍历中完成任务?

记住:有时看似复杂的问题,用合适的思维方式就能找到优雅的解决方案。


作者:忍者算法
公众号:忍者算法

我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/890417.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows系统更改/迁移用户目录

Windows系统更改/迁移用户目录Windows系统更改/迁移用户目录 迁移的原因C盘空间不足 不想将我的文档等放在C盘,方便重做系统 其他原因迁移有什么风险么目前没发现有什么风险迁移过程 准备工作 更改/迁移用户目录之前先自行备份当前用户的资料(下载目录、桌面文件等),以免数…

[2025.2.26 JavaWeb学习]登录校验

流程图会话技术指浏览器与服务器的一次连接,直到某一方断开,某个浏览器的一次会话可以包含多次请求和响应会话跟踪:一种维护浏览器状态的方法,服务器需要识别多次请求是否来自于同一浏览器,以便在同一次会话的多次请求间共享数据

cmcc_simplerop

打开ida查看,可以看到是静态编译,所以无法常规用ret2libc此时可以用最简单的方法系统调用 首先ida上面的偏移量是错误的,我们手动用gdb算一下距离ebp为0x1c因为要实现execve("/bin/sh",0,0)找int 0x80,eax,ebx,ecx,edx因为程序里面没有binsh或sh,所以我们得手动…

day4复健-字符串

题目练习:反转字符串 知识学习: StringBuilder:内容可变的字符串容器StringJoiner练习: 阿拉伯数字转换为罗马数字练习2:练习3:

软件开发与创新——万年历功能新增与代码优化

一、项目名称与来源 上海海洋大学C语言期末大作业 二、原项目运行 运行环境: 系统:Windows11 24H2 cpu:i7-10750H 编译器:Dev c++ 5.11 运行结果:点击查看代码 #include <stdio.h> #include <stdlib.h>// 定义每个月的天数,第一行为平年,第二行为闰年 int d…

逆向软件设计和开发---学生信息管理程序

一、来源 源代码来自同学大一上学期C语言大作业 二、运行环境 Dev-C++ 6.3 三、源代码及运行结果 1.源代码点击查看代码 #include <stdio.h> #include <stdlib.h> #include <string.h>#define MAX_NAME_LENGTH 20 #define MAX_SCORE_COUNT 5// 学生信息结构体…

在鹅厂做java开发是什么体验

离职已有好几个月,准备写一篇关于之前在腾讯做Java开发的经历,现在来谈谈在Java领域里,在腾讯做Java开发的体验。随便写写别较真。首先,介绍一下腾讯里与Java相关的部门。主要有CDG(云与智慧产业事业群)中的腾讯广告和FIT(金融科技事业群)理财通。其他部门则包括TEG中的…

软件二次开发

软件来源:舍友期末大作业 软件运行环境:dev C++ 软件运行图: 软件伸缩代码图: 问题:菜单只会出现一次,在多次操作之后菜单会被顶走,届时用户只能依照记忆操作系统 更改的代码: 在循环执行选项的代码部分增加了菜单的输出 更改后的代码运行:

换根dp

概念 换根 \(dp\) ,又被称为二次扫描,是属于树形 \(dp\) 的一类但比一般树形dp更难。 特点通常是没有指定根结点,且根结点的变化会对一些值产生影响。通常需要两次 \(dfs\) ,第一次 \(dfs\) 预处理信息,第二次 \(dfs\) 开始换根动态规划。求解的答案通常需要结合所有相连的…

千锋教育MyBatisPlus全套课程,简单快速一套精通MyBatisPlus框架(代码生成器_引入_使用)

https://www.bilibili.com/video/BV1aa4y1A7iN?spm_id_from=333.788.videopod.episodes&vd_source=0d7b1712ce42c1a2fa54bb4e1d601d78代码生成器_引入_使用 https://github.com/godmaybelieve

【PLSQL】使用PLSQL查看创表SQL踩坑

背景 通过PL/SQL Developer的View SQL查看表的创表语句,结果发现创表语句少了字段 可能原因PL/SQL Developer 的对象浏览器会缓存元数据信息以提高性能。如果修改表结构后未手动刷新,工具可能继续展示缓存中的旧元数据。 Oracle 的数据字典视图(如 USER_TAB_COLUMNS)本身是…

从 0 到 Offer:Dynamics 365 CRM 学员的普华永道逆袭之路

在竞争激烈的就业市场中,如何才能脱颖而出,收获理想的工作?李先顺(化名)的经历或许能给我们带来深刻的启示。这位出身普通高校信息管理专业的应届毕业生,通过在爱码士IT培训www.aimashi365.com机构的报名和培训,凭借着对 Dynamics 365 CRM 技术的深入学习和实践,成功入…