给你一个链表,删除链表的倒数第 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 <= 300 <= Node.val <= 1001 <= n <= sz
解法思路
- 虚拟头节点 :创建
dummy节点指向原链表头,避免删除头节点时的特殊处理(如输入head=[1], n=1的情况)。 - 双指针初始化 :
fast和slow都从dummy开始。 - 快指针先行 :让
fast先向前走n步,拉开与slow的距离。 - 同步移动指针 :
fast和slow同时前进,直到fast到达链表末尾(fast.next为None)。此时slow的下一个节点,就是链表的倒数第 N 个节点。 - 删除节点 :将
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测试,适用于所有合法输入情况。