You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何删除链表倒数第N个节点的代码在IDE正常但LeetCode报错?

解决删除链表倒数第N个节点的运行时错误问题

你的代码在本地测试用例(链表长度5,n=2)能正常运行,但提交到LeetCode后报错,核心问题是没处理「删除头节点」的边界情况,逻辑上存在空指针访问的风险:

错误原因分析

你的代码试图通过指针的指针buf定位到要删除节点的前一个位置,但当n等于链表总长度时(比如链表仅1个节点,n=1),循环n次后buf会指向head->next的地址(也就是&nullptr),此时(*buf)是nullptr,执行(*buf) = (*buf)->next就会触发空指针成员访问错误——这正是LeetCode测试用例命中的场景。

修正方案:快慢指针法

用哑节点+快慢指针可以完美处理所有边界情况,步骤如下:

  • 创建哑节点指向原链表头,避免单独处理删除头节点的逻辑;
  • 快指针先向前走n步;
  • 快慢指针同步前进,直到快指针走到链表末尾;
  • 此时慢指针的next就是要删除的节点,直接跳过该节点;
  • 返回哑节点的next作为新链表头。

修正后的代码

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) {}
};

ListNode* removeNthFromEnd(ListNode* head, int n) {
    // 创建哑节点,统一处理删除头节点的情况
    ListNode* dummy = new ListNode(0, head);
    ListNode* fast = dummy;
    ListNode* slow = dummy;

    // 快指针先走n步
    for (int i = 0; i < n; ++i) {
        fast = fast->next;
    }

    // 快慢指针同步走,直到快指针到末尾
    while (fast->next != nullptr) {
        fast = fast->next;
        slow = slow->next;
    }

    // 跳过要删除的节点
    slow->next = slow->next->next;
    ListNode* newHead = dummy->next;
    delete dummy; // 释放哑节点内存
    return newHead;
}

int main() {
    removeNthFromEnd(new ListNode(1, new ListNode(2, new ListNode(3, new ListNode(4, new ListNode(5))))), 2);
    return 0;
}

额外说明

  • 哑节点的作用是让删除头节点的逻辑和删除其他节点完全一致,无需单独判断;
  • 快慢指针法仅遍历链表一次,时间复杂度O(L)(L为链表长度),空间复杂度O(1),是最优解法;
  • 原代码逻辑可调整但需增加合法性判断,相比之下快慢指针写法更简洁且不易出错。

内容的提问来源于stack exchange,提问作者njnjfnj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 23:55:21