力扣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),不需要额外空间

  • 代码简洁,逻辑清晰

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

相关推荐
前端小L4 小时前
贪心算法专题(十):维度权衡的艺术——「根据身高重建队列」
javascript·算法·贪心算法
方得一笔4 小时前
自定义常用的字符串函数(strlen,strcpy,strcmp,strcat)
算法
Xの哲學4 小时前
Linux SMP 实现机制深度剖析
linux·服务器·网络·算法·边缘计算
wuk9985 小时前
使用PCA算法进行故障诊断的MATLAB仿真
算法·matlab
额呃呃5 小时前
二分查找细节理解
数据结构·算法
无尽的罚坐人生5 小时前
hot 100 283. 移动零
数据结构·算法·双指针
永远都不秃头的程序员(互关)5 小时前
C++动态数组实战:从手写到vector优化
c++·算法
水力魔方6 小时前
武理排水管网模拟分析系统应用专题5:模型克隆与并行计算
数据库·c++·算法·swmm
谈笑也风生6 小时前
经典算法题型之排序算法(三)
java·算法·排序算法
大佬,救命!!!8 小时前
对算子shape相关的属性值自动化处理
python·算法·自动化·学习笔记·算子·用例脚本·算子形状