LeetCode 热题 100 | 19. 删除链表的倒数第 N 个结点
大家好,今天我们来解决一道经典的链表问题——删除链表的倒数第 N 个结点。这道题在 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
解题思路
核心思想
-
双指针法:
- 使用两个指针
first
和second
,初始时都指向链表的头结点。 - 先让
first
指针向前移动n
步。 - 然后同时移动
first
和second
指针,直到first
指针到达链表末尾。 - 此时,
second
指针的下一个节点就是需要删除的节点。
- 使用两个指针
-
删除节点:
- 将
second.next
指向second.next.next
,从而跳过需要删除的节点。
- 将
-
特殊情况:
- 如果
n
等于链表的长度,即删除头结点,直接返回head.next
。
- 如果
Python代码实现
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
# 创建一个虚拟头结点
dummy = ListNode(0)
dummy.next = head
# 初始化两个指针
first = dummy
second = dummy
# 让 first 指针向前移动 n + 1 步
for _ in range(n + 1):
first = first.next
# 同时移动 first 和 second 指针,直到 first 到达链表末尾
while first:
first = first.next
second = second.next
# 删除 second 的下一个节点
second.next = second.next.next
return dummy.next
代码解析
-
虚拟头结点:
- 创建一个虚拟头结点
dummy
,并将其next
指向链表的头结点。这可以简化删除头结点的特殊情况。
- 创建一个虚拟头结点
-
初始化指针:
- 初始化两个指针
first
和second
,都指向虚拟头结点。
- 初始化两个指针
-
移动指针:
- 让
first
指针向前移动n + 1
步。 - 同时移动
first
和second
指针,直到first
指针到达链表末尾。
- 让
-
删除节点:
- 将
second.next
指向second.next.next
,从而跳过需要删除的节点。
- 将
-
返回结果:
- 返回
dummy.next
,即删除节点后的链表头结点。
- 返回
复杂度分析
- 时间复杂度:O(L),其中
L
是链表的长度。只需要遍历链表一次。 - 空间复杂度:O(1),只使用了常数级别的额外空间。
示例运行
示例 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]
总结
通过双指针法,我们可以高效地删除链表的倒数第 n
个结点。这种方法在 O(L) 时间复杂度内完成,并且只使用了 O(1) 的额外空间。希望这篇题解对大家有所帮助,如果有任何问题,欢迎在评论区留言讨论!
关注我,获取更多算法题解和编程技巧!