19. 删除链表的倒数第 N 个结点

102 阅读1分钟

题目

🔗题目链接:19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

给你一个链表,删除链表的倒数第 n **个结点,并且返回链表的头结点。

示例 1:

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

示例 2:

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

示例 3:

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

提示:

  • 链表中结点的数目为 sz
  • 1 <= sz <= 30
  • 0 <= Node.val <= 100
  • 1 <= n <= sz

进阶: 你能尝试使用一趟扫描实现吗?

思路

使用虚拟头节点,这样就不用单独处理头节点了。

使用快慢指针(双指针)。快指针先走 n 步,然后再走一步。然后快慢指针在快指针指向的元素不为空的时候一直往链表结尾走。当快指针指向空时,慢指针刚好走到要删除的节点的前一个节点。

代码

function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
  if (!head) return head;

  const dummyHead = new ListNode(0, head);
  let fast: ListNode | null = dummyHead;
  let slow = dummyHead;
  let step = n;

  // 快指针先往前走 n 步
  while (step > 0 && fast) {
    fast = fast.next;

    step--;
  }

  // step 大于 0, 说明 n 大于链表的长度,不用移除元素
  if (step > 0) return dummyHead.next;

  // 让 fast 再往后走一步,这时 slow 刚好指向要移除的元素的前一个元素
  fast = (fast as ListNode).next;

  // 当 fast === null 时,
  // 慢指针刚好移动到要移除的元素的前一个元素
  while (fast) {
    // 这时 fast 移动到链表末尾
    fast = fast.next;
    slow = slow.next as ListNode;
  }

  slow.next = (slow.next as ListNode).next;

  return dummyHead.next;
}