每日一题:删除链表的倒数第 N 个结点

每日一题:删除链表的倒数第 N 个结点
最新回答
我怕冷抱紧我

2026-10-23 06:54:21

要删除链表的倒数第N个结点,可以使用双指针技巧。以下是详细的解题思路和代码实现:

解题思路
  1. 创建虚拟头节点:为了方便处理删除头节点的情况,创建一个虚拟头节点dummy,其next指向真正的头节点head。
  2. 初始化指针:定义两个指针left和right,初始时都指向dummy。
  3. 移动右指针:先将right指针向右移动n步,这样left和right之间相隔n个节点。
  4. 同步移动指针:然后同时移动left和right指针,直到right指向链表末尾(即right.next为null)。此时,left指向要删除节点的前一个节点。
  5. 删除节点:通过left.next = left.next.next删除目标节点。
  6. 返回结果:返回dummy.next,即新的头节点。
代码实现(Java)class ListNode { int val; ListNode next; ListNode(int x) { val = x; }}public class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { ListNode dummy = new ListNode(-1); dummy.next = head; ListNode left = dummy; ListNode right = dummy; // 移动右指针n步 for (int i = 0; i < n; i++) { right = right.next; } // 同步移动左右指针,直到右指针到达末尾 while (right.next != null) { left = left.next; right = right.next; } // 删除目标节点 left.next = left.next.next; return dummy.next; }}复杂度分析
  • 时间复杂度:O(n),其中n是链表的长度。我们只需要遍历链表两次(移动右指针和同步移动指针)。
  • 空间复杂度:O(1),只使用了常数级别的额外空间。
示例验证
  1. 示例1:

    输入:head = [1,2,3,4,5], n = 2

    过程:

    初始:dummy -> 1 -> 2 -> 3 -> 4 -> 5

    移动right 2步:right指向2。

    同步移动left和right直到right.next为null:

    left移动到3,right移动到4。

    left移动到4,right移动到5。

    删除left.next(即5的前一个节点4的下一个节点5):4 -> null变为4.next = 5.next(即null)。

    输出:[1,2,3,5]

  2. 示例2:

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

    过程:

    初始:dummy -> 1

    移动right 1步:right指向1。

    同步移动left和right直到right.next为null:

    left和right都指向1,但right.next为null,循环结束。

    删除left.next(即1):dummy.next = 1.next(即null)。

    输出:[]

  3. 示例3:

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

    过程:

    初始:dummy -> 1 -> 2

    移动right 1步:right指向1。

    同步移动left和right直到right.next为null:

    left移动到1,right移动到2。

    删除left.next(即2):1.next = 2.next(即null)。

    输出:[1]

关键点
  • 虚拟头节点:简化删除头节点的操作。
  • 双指针间隔:通过间隔n步确保left指向目标节点的前一个节点。
  • 同步移动:确保right到达末尾时,left位置正确。

这种方法高效且易于理解,适用于大多数链表操作问题。