面试经典150题[063]:删除链表的倒数第 N 个结点(LeetCode 19)

删除链表的倒数第 N 个结点(LeetCode 19)

题目链接:删除链表的倒数第 N 个结点(LeetCode 19)

难度:中等

1. 题目描述

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

要求:

  • 链表中每个结点的值都是唯一的
  • 1 <= 链表长度 <= 30
  • 1 <= n <= 链表长度
  • 题目保证 n 是有效的(即一定能删除)

示例:

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

输入:head = [1], n = 1
输出:[]

输入:head = [1,2], n = 1
输出:[1]

2. 问题分析

2.1 规律

  • 链表是单向的,无法直接从尾部访问。
  • 倒数第 n 个结点 → 正数第 L - n + 1 个(L 为链表长度),但计算长度需要两遍遍历。
  • 核心问题:如何一次遍历找到倒数第 n 个结点?

2.2 快慢指针(双指针)思路

使用 快慢指针 技巧,一次遍历解决:

  • fast 先走 n 步。
  • 然后 slowfast 同时向前走,直到 fast 到达末尾(fast.next == null)。
  • 此时 slow 恰好位于 倒数第 n+1 个结点 (因为 fastslow 超前 n 步)。
  • 删除 slow.next 即可。

特殊处理

  • 如果删除的是头结点(即 n 等于链表长度),直接返回 head.next
  • 使用 虚拟头结点(dummy head) 可统一处理所有情况,避免单独判断头结点。

3. 代码实现

Python

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: ListNode, n: int) -> ListNode:
        # 创建虚拟头结点,简化删除头结点的逻辑
        dummy = ListNode(0, head)
        fast = slow = dummy
        
        # fast 先走 n 步
        for _ in range(n):
            fast = fast.next
        
        # fast 和 slow 一起走,直到 fast 到末尾
        while fast.next:
            fast = fast.next
            slow = slow.next
        
        # slow.next 就是要删除的结点
        slow.next = slow.next.next
        
        return dummy.next

C++

cpp 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        // 虚拟头结点
        ListNode* dummy = new ListNode(0, head);
        ListNode* fast = dummy;
        ListNode* slow = dummy;
        
        // fast 先走 n 步
        for (int i = 0; i < n; ++i) {
            fast = fast->next;
        }
        
        // 一起走,直到 fast 到最后一个结点
        while (fast->next) {
            fast = fast->next;
            slow = slow->next;
        }
        
        // 删除 slow 的下一个结点
        ListNode* temp = slow->next;
        slow->next = slow->next->next;
        delete temp;
        
        ListNode* result = dummy->next;
        delete dummy;  // 可选:释放虚拟头结点
        return result;
    }
};

4. 复杂度分析

  • 时间复杂度 :O(L),其中 L 是链表长度。只遍历一次。
  • 空间复杂度:O(1),只使用了常数额外空间(虚拟头结点可忽略)。

5. 总结

  • 倒数第 n 个快慢指针 是标配
  • 使用 虚拟头结点 统一处理边界(删除头结点)
  • 类似题目:
    • 环形链表 II(快慢指针找入口)
    • 链表中点(LeetCode 876)
  • 可扩展:删除倒数第 n 个后 重建链表返回被删结点值

复习

面试经典150题[003]:删除有序数组中的重复项(LeetCode 26)

面试经典150题[033]:最小覆盖子串(LeetCode 76)

面试经典150题[048]:汇总区间(LeetCode 228)

相关推荐
jinmo_C++23 分钟前
Leetcode_59. 螺旋矩阵 II
算法·leetcode·矩阵
夏鹏今天学习了吗24 分钟前
【LeetCode热题100(81/100)】零钱兑换
算法·leetcode·职场和发展
清 澜1 小时前
大模型扫盲式面试知识复习 (二)
人工智能·面试·职场和发展·大模型
wifi chicken2 小时前
Linux 内核开发之单链表的增删查改详解
linux·数据结构·链表
踩坑记录2 小时前
leetcode hot100 238.除了自身以外数组的乘积 medium
leetcode
掘金安东尼2 小时前
⏰前端周刊第 448 期(2026年1月4日-1月10日)
前端·面试·github
邹阿涛涛涛涛涛涛2 小时前
月之暗面招聘 Android
面试·招聘
海天一色y2 小时前
python---力扣数学部分
算法·leetcode·职场和发展
一起努力啊~2 小时前
算法刷题--哈希表
算法·面试·散列表
踩坑记录3 小时前
leetcode hot100 56.合并区间 medium
leetcode