【LeetCode刷题】删除链表的倒数第N个结点

给你一个链表,删除链表的倒数第 n个结点,并且返回链表的头结点。

示例 1:

复制代码
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]

示例 2:

复制代码
输入:head = [1], n = 1
输出:[]

示例 3:

复制代码
输入:head = [1,2], n = 1
输出:[1]

提示:

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

解法思路

  1. 虚拟头节点 :创建dummy节点指向原链表头,避免删除头节点时的特殊处理(如输入head=[1], n=1的情况)。
  2. 双指针初始化fastslow都从dummy开始。
  3. 快指针先行 :让fast先向前走n步,拉开与slow的距离。
  4. 同步移动指针fastslow同时前进,直到fast到达链表末尾(fast.nextNone)。此时slow的下一个节点,就是链表的倒数第 N 个节点
  5. 删除节点 :将slow.next指向slow.next.next,完成节点删除。

核心优势

  • 时间复杂度 O (L):仅遍历链表一次(L 为链表长度),比 "先统计长度再删除" 的两次遍历更高效。
  • 边界全覆盖:通过虚拟头节点,完美处理 "删除头节点""链表长度为 1" 等特殊情况。

Python代码

python 复制代码
# 导入必要的类型注解模块
from typing import Optional


# 完整定义单链表节点类
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

    # 可选:添加打印链表的辅助方法(方便测试)
    def __str__(self):
        result = []
        current = self
        while current:
            result.append(str(current.val))
            current = current.next
        return " -> ".join(result)


# 核心解题类
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        # 虚拟头节点:避免删除头节点时的边界处理
        dummy = ListNode(0)
        dummy.next = head
        fast = dummy
        slow = dummy

        # 步骤1:快指针先向前走n步
        for _ in range(n):
            fast = fast.next

        # 步骤2:快慢指针同时前进,直到快指针到达链表末尾
        while fast.next:
            fast = fast.next
            slow = slow.next

        # 步骤3:删除慢指针的下一个节点(倒数第n个节点)
        slow.next = slow.next.next

        # 返回新的头节点(虚拟头节点的下一个)
        return dummy.next


# 辅助函数:将列表转换为链表(方便测试)
def list_to_linkedlist(arr):
    if not arr:
        return None
    head = ListNode(arr[0])
    current = head
    for val in arr[1:]:
        current.next = ListNode(val)
        current = current.next
    return head


# 测试用例
if __name__ == "__main__":
    # 测试用例1:常规情况
    arr1 = [1, 2, 3, 4, 5]
    n1 = 2
    head1 = list_to_linkedlist(arr1)
    print("原链表1:", head1)
    solution = Solution()
    new_head1 = solution.removeNthFromEnd(head1, n1)
    print(f"删除倒数第{n1}个节点后:", new_head1)  # 预期输出:1 -> 2 -> 3 -> 5

    # 测试用例2:删除头节点
    arr2 = [1, 2]
    n2 = 2
    head2 = list_to_linkedlist(arr2)
    print("\n原链表2:", head2)
    new_head2 = solution.removeNthFromEnd(head2, n2)
    print(f"删除倒数第{n2}个节点后:", new_head2)  # 预期输出:2

    # 测试用例3:链表只有一个节点
    arr3 = [1]
    n3 = 1
    head3 = list_to_linkedlist(arr3)
    print("\n原链表3:", head3)
    new_head3 = solution.removeNthFromEnd(head3, n3)
    print(f"删除倒数第{n3}个节点后:", new_head3)  # 预期输出:None

LeetCode提交代码

python 复制代码
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        # 虚拟头节点:避免删除头节点时的边界处理
        dummy = ListNode(0)
        dummy.next = head
        fast = dummy
        slow = dummy
        
        # 步骤1:快指针先向前走n步
        for _ in range(n):
            fast = fast.next
        
        # 步骤2:快慢指针同时前进,直到快指针到达链表末尾
        while fast.next:
            fast = fast.next
            slow = slow.next
        
        # 步骤3:删除慢指针的下一个节点
        slow.next = slow.next.next
        
        # 返回新的头节点(虚拟头节点的下一个)
        return dummy.next

程序运行结果展示

原链表1: 1 -> 2 -> 3 -> 4 -> 5

删除倒数第2个节点后: 1 -> 2 -> 3 -> 5

原链表2: 1 -> 2

删除倒数第2个节点后: 2

原链表3: 1

删除倒数第1个节点后: None

总结

本文介绍了一种高效删除链表倒数第N个节点的双指针解法。通过创建虚拟头节点处理边界情况,使用快慢指针实现一次遍历:快指针先走N步,然后两指针同步移动直至链表末尾,此时慢指针的下一个节点即为待删除节点。该方法时间复杂度O(L)(L为链表长度),优于两次遍历的解法,且能完美处理删除头节点等特殊情况。文中提供了Python实现代码,包含链表转换、测试用例及运行结果验证,确保算法正确性和鲁棒性。该解法已通过LeetCode测试,适用于所有合法输入情况。

相关推荐
BHXDML5 小时前
推导神经网络前向后向传播算法的优化迭代公式
神经网络·算法·机器学习
叫我:松哥5 小时前
基于YOLO深度学习算法的人群密集监测与统计分析预警系统,实现人群密集度的实时监测、智能分析和预警功能,支持图片和视频流两种输入方式
人工智能·深度学习·算法·yolo·机器学习·数据分析·flask
Non-existent9875 小时前
地理空间数据处理指南 | 实战案例+代码TableGIS
人工智能·python·数据挖掘
你撅嘴真丑5 小时前
STL练习
开发语言·c++·算法
苦藤新鸡5 小时前
28.两数相加,进位制
数据结构·算法·链表·力扣
Lips6115 小时前
第七章 贝叶斯分类器
人工智能·算法·机器学习
无限进步_5 小时前
二叉搜索树(BST)详解:从原理到实现
开发语言·数据结构·c++·ide·后端·github·visual studio
xj7573065335 小时前
python中的序列化
服务器·数据库·python
郝学胜-神的一滴5 小时前
机器学习特征选择:深入理解移除低方差特征与sklearn的VarianceThreshold
开发语言·人工智能·python·机器学习·概率论·sklearn