为何删除链表倒数第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
相关产品推荐
相关产品推荐

