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

问题描述

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

示例 1:

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

提示:

  • 1 <= head.length <= 100

  • 0 <= head[i] <= 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),不需要额外空间

  • 代码简洁,逻辑清晰

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

相关推荐
程序员-King.6 小时前
day158—回溯—全排列(LeetCode-46)
算法·leetcode·深度优先·回溯·递归
月挽清风7 小时前
代码随想录第七天:
数据结构·c++·算法
小O的算法实验室7 小时前
2026年AEI SCI1区TOP,基于改进 IRRT*-D* 算法的森林火灾救援场景下直升机轨迹规划,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
小郭团队8 小时前
2_1_七段式SVPWM (经典算法)算法理论与 MATLAB 实现详解
嵌入式硬件·算法·硬件架构·arm·dsp开发
充值修改昵称8 小时前
数据结构基础:从二叉树到多叉树数据结构进阶
数据结构·python·算法
Deepoch8 小时前
Deepoc数学大模型:发动机行业的算法引擎
人工智能·算法·机器人·发动机·deepoc·发动机行业
浅念-9 小时前
C语言小知识——指针(3)
c语言·开发语言·c++·经验分享·笔记·学习·算法
Hcoco_me9 小时前
大模型面试题84:是否了解 OpenAI 提出的Clip,它和SigLip有什么区别?为什么SigLip效果更好?
人工智能·算法·机器学习·chatgpt·机器人
BHXDML9 小时前
第九章:EM 算法
人工智能·算法·机器学习
却道天凉_好个秋10 小时前
目标检测算法与原理(三):PyTorch实现迁移学习
pytorch·算法·目标检测