1. 删除链表的倒数第 N 个节点(LeetCode 19)中双指针间距 N 的一次遍历法,如何处理删除头节点的边界
给定一个单链表,要求删除其倒数第 N 个节点,并说明如何使用双指针在一次遍历中完成,以及如何处理删除头节点时的边界情况?
- 双指针间距 N 的滑动技巧
- 虚拟头节点(dummy node)的边界处理
- 指针操作的正确性
使用两个指针 fast 和 slow,先让 fast 前进 N 步,使 fast 与 slow 之间相隔 N 个节点;然后 fast 和 slow 同时前进,当 fast 到达链表末尾时,slow 恰好指向倒数第 N 个节点的前一个节点,此时修改 slow.next 即可完成删除。为了让删除头节点也能统一处理,可在链表前加一个虚拟头节点 dummy,slow 从 dummy 出发,这样 fast 与 slow 之间始终隔 N 个节点,fast 到末尾时 slow 正好在待删节点的前驱,无需特判头节点。
关键是把"倒数第 N 个"转化为"与末尾相差 N-1 个节点",通过固定间距让慢指针停在待删节点的前驱。若不使用 dummy,删除头节点时前驱为 null,需要单独判断,容易出错;dummy 使所有情况统一。
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0, head);
ListNode fast = dummy, slow = dummy;
for (int i = 0; i < n; i++) fast = fast.next;
while (fast.next != null) {
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}