移除链表倒数第N个节点:双次遍历法空指针错误排查
解决移除链表倒数第N个节点时的空指针错误
你的代码核心问题
- 循环逻辑完全错误:统计完节点总数
count后,你复用count作为第二个循环的终止条件,while(count>0)会让ptr一直走到链表末尾的next(也就是nullptr),后续访问ptr->next必然触发空指针错误。你应该用计算好的remove = count -n -1来控制循环,移动到要删除节点的前一个位置。 - 未处理删除头节点的边界情况:当要删除的是链表第一个节点(即
n == count)时,remove = count -n -1 = -1,不存在“前一个节点”,此时直接返回head->next即可,不能再操作ptr->next。 - 变量复用导致原数据丢失:统计节点数的
count被你在第二个循环中修改,后续无法再获取原节点总数,应该用临时变量做循环计数。
修正后的代码
/** * 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) { int count = 0; ListNode *ptr = head; // 第一次遍历统计节点总数 while (ptr != nullptr) { count++; ptr = ptr->next; } // 处理删除头节点的特殊情况 if (n == count) { ListNode* temp = head; head = head->next; delete temp; // 可选:释放内存避免泄漏 return head; } // 计算需要移动到的位置:倒数第n个节点的前一个 int steps = count - n - 1; ptr = head; // 移动到目标位置 while (steps > 0) { ptr = ptr->next; steps--; } // 删除目标节点 ListNode* temp = ptr->next; ptr->next = ptr->next->next; delete temp; // 可选:释放内存 return head; } };
额外优化:单次遍历的快慢指针法
如果想进一步提升效率,可以用快慢指针只遍历一次链表:让快指针先走n步,之后快慢指针同步移动,当快指针走到链表末尾时,慢指针刚好指向倒数第n个节点的前一个位置,无需统计节点总数。示例代码如下:
class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { // 用哑节点简化头节点删除的处理逻辑 ListNode* dummy = new ListNode(0, head); ListNode* fast = dummy; ListNode* slow = dummy; // 快指针先走n+1步 for (int i = 0; i <= n; i++) { fast = fast->next; } // 快慢指针同步移动,直到快指针到达末尾 while (fast != nullptr) { fast = fast->next; slow = slow->next; } // 删除目标节点 ListNode* temp = slow->next; slow->next = slow->next->next; delete temp; ListNode* newHead = dummy->next; delete dummy; return newHead; } };
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

