力扣140.快慢指针法求解链表倒数第K个节点

问题描述

给定一个头节点为 head 的链表,用于记录一系列核心肌群训练项目编号,请查找并返回倒数第 cnt 个训练项目编号。

示例 1:

复制代码
输入:head = [2,4,7,8], cnt = 1
输出:8

提示:

  • 1 <= head.length <= 100

  • 0 <= headi <= 100

  • 1 <= cnt <= head.length

问题分析

这是一个经典的链表问题,要求找到链表中倒数第 cnt 个节点。链表的特点是只能顺序访问,不能像数组那样直接通过索引访问。因此,我们需要一种高效的算法来解决这个问题。

解决方案:快慢指针法

算法思路

使用两个指针 fastslow,都初始化为头节点:

  1. 先让 fast 指针向前移动 cnt

  2. 然后同时移动 fastslow 指针,直到 fast 到达链表末尾

  3. 此时 slow 指针指向的就是倒数第 cnt 个节点

算法原理

这个算法的巧妙之处在于利用了"距离差"的原理。当 fast 指针先走 cnt 步后,fastslow 之间相隔 cnt 个节点。然后两个指针以相同的速度前进,当 fast 到达链表末尾时,slow 正好落后 fast 指针 cnt 个节点,也就是位于倒数第 cnt 个位置。

代码实现

python 复制代码
class Solution:
    def trainingPlan(self, head: Optional[ListNode], cnt: int) -> Optional[ListNode]:
        # 初始化快慢指针
        fast = slow = head
        
        # 快指针先走cnt步
        while cnt > 0 and fast:
            fast = fast.next
            cnt -= 1
        
        # 同时移动快慢指针,直到快指针到达末尾
        while fast:
            fast = fast.next
            slow = slow.next
        
        return slow

算法复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。我们只需要遍历链表一次。

  • 空间复杂度:O(1),只使用了常数级别的额外空间。

算法详解

示例演示

以链表 2 -> 4 -> 7 -> 8cnt = 2 为例(找倒数第2个节点):

  1. 初始化:fast = slow = 节点2

  2. 快指针先走2步:

    • 第一步:fast = 节点4cnt = 1

    • 第二步:fast = 节点7cnt = 0

  3. 同时移动两个指针:

    • fast = 节点8slow = 节点4

    • fast = Noneslow = 节点7

  4. 返回 slow(节点7,值为7)

边界情况处理

  1. cnt等于链表长度 :当 cnt 等于链表长度时,快指针会走到链表末尾(fast = None),慢指针仍指向头节点,正好是倒数第 cnt 个节点。

  2. cnt等于1 :当 cnt = 1 时,找到的是最后一个节点。

  3. 链表只有一个节点 :无论 cnt 是多少(只能是1),都能正确返回该节点。

其他解法对比

解法一:两次遍历法

先遍历链表得到长度 n,然后再遍历到第 n-cnt 个节点。

python

复制代码
class Solution:
    def trainingPlan(self, head: Optional[ListNode], cnt: int) -> Optional[ListNode]:
        # 第一次遍历:计算链表长度
        length = 0
        cur = head
        while cur:
            length += 1
            cur = cur.next
        
        # 第二次遍历:找到第length-cnt个节点
        cur = head
        for _ in range(length - cnt):
            cur = cur.next
        
        return cur

复杂度:时间复杂度 O(2n) = O(n),空间复杂度 O(1)。

解法二:使用栈

遍历链表,将所有节点压入栈中,然后弹出前 cnt 个节点,第 cnt 个弹出的就是目标节点。

python

复制代码
class Solution:
    def trainingPlan(self, head: Optional[ListNode], cnt: int) -> Optional[ListNode]:
        stack = []
        cur = head
        while cur:
            stack.append(cur)
            cur = cur.next
        
        # 弹出前cnt-1个节点
        for _ in range(cnt - 1):
            stack.pop()
        
        return stack.pop()

复杂度:时间复杂度 O(n),空间复杂度 O(n)。

解法比较

方法 时间复杂度 空间复杂度 优点 缺点
快慢指针法 O(n) O(1) 效率高,空间优 思路需要理解
两次遍历法 O(2n) O(1) 思路简单直接 需要两次遍历
栈方法 O(n) O(n) 思路简单 需要额外空间

实际应用

这个问题在实际开发中有着广泛的应用:

  1. 查找中间节点:类似思路可以找到链表的中间节点

  2. 检测链表环:快慢指针法也可用于检测链表是否有环

  3. 数据库查询优化:在处理链表形式的数据时,类似算法可以提高效率

总结

快慢指针法是解决链表倒数第K个节点问题的最优解,它具有以下优点:

  • 时间复杂度为 O(n),只需遍历一次链表

  • 空间复杂度为 O(1),不需要额外空间

  • 代码简洁,逻辑清晰

掌握这种双指针技巧对于解决链表相关问题非常有帮助,它是算法面试中的常考知识点,也是实际开发中处理链表数据的高效方法。

相关推荐
枫叶林FYL38 分钟前
【群体智能集群控制工程实践】第3章 一致性协同算法
算法
禹凕1 小时前
滑动窗口算法实战指南
python·算法
DisonTangor1 小时前
【腾讯混元雪耻归来】 Hy4 preview:770B 参数 MoE 旗舰模型,1M 上下文全面开源
人工智能·算法·开源·aigc·腾讯云·腾讯云ai代码助手
明月_清风2 小时前
从二叉树到 B+ 树:一文搞懂工程中「树」的演化之道
数据结构·算法·go
渡我白衣2 小时前
并查集:基础认识与模拟实现
android·java·javascript·数据结构·c++·算法·并查集
hetao17338373 小时前
2026-09-01~09-04 hetao1733837 的刷题记录
c++·算法
Evand J3 小时前
【MATLAB例程,图像滤波5】 反谐波均值滑动窗口滤波(CHMF)图像降噪与质量评价,附代码下载链接
图像处理·算法·计算机视觉·matlab·均值算法·滑动窗口滤波·均值滑动
血小板要健康3 小时前
链表 阶段算法总结
java·数据结构·笔记·算法·leetcode·链表
a187927218313 小时前
【算法】回溯算法(三):三记重锤与 N 皇后——记忆化、状态设计与三层漏斗
算法·leetcode·go·剪枝·回溯·n皇后·算法讲解
HugoStudio_SWAN5 小时前
洛谷 P1420 / P1179 / B4262 最长连号、数字统计与词频统计——统计的三种面孔
c++·学习·程序人生·算法