返回

一招解决:删除链表倒数第 N 个结点

前端

在数据结构的世界中,链表是一种线性的数据结构,其中每个结点包含一个值和指向下一个结点的指针。链表经常用于各种应用中,例如存储数据、实现队列或栈,甚至是模拟文件系统。

有时候,我们可能会需要从链表中删除特定的结点,例如删除链表的倒数第 N 个结点。这个任务可能看起来有些棘手,尤其是当我们希望仅使用一次遍历来完成它的时候。

一网打尽:一次遍历解决问题

要一次性解决这个问题,我们可以采用以下步骤:

  1. 创建一个虚拟头结点,将其指向链表的第一个结点。这个虚拟头结点将帮助我们简化边界条件的处理。
  2. 使用两个指针,precur,分别指向虚拟头结点和链表的第一个结点。
  3. cur 指针向前移动 n 步,从而与要删除的结点保持 n 个结点的距离。
  4. cur 指针到达链表的末尾时,pre 指针将指向要删除结点的前一个结点。
  5. 更新 pre 指针的 next 指针,使其指向要删除结点的下一个结点,从而有效地从链表中删除了该结点。

代码实现:

def remove_nth_from_end(head, n):
  """
  删除链表的倒数第 n 个结点
  
  Args:
    head: 链表头结点
    n: 要删除的结点距离链表末尾的距离
  
  Returns:
    删除结点后的链表头结点
  """

  # 创建虚拟头结点
  dummy = ListNode(0, head)

  # 初始化 pre 和 cur 指针
  pre = dummy
  cur = head

  # 让 cur 指针向前移动 n 步
  for _ in range(n):
    cur = cur.next

  # 当 cur 指针到达链表末尾时,pre 指针指向要删除结点的前一个结点
  while cur:
    pre = pre.next
    cur = cur.next

  # 删除结点
  pre.next = pre.next.next

  # 返回虚拟头结点的下一个结点,即链表的新头结点
  return dummy.next

举例说明

假设我们有一个链表 1 -> 2 -> 3 -> 4 -> 5,我们需要删除倒数第二个结点(n = 2)。

  1. 创建虚拟头结点 dummy,指向链表的第一个结点 1
  2. 初始化 precur 指针,分别指向 dummy1
  3. cur 指针向前移动 n = 2 步,到达结点 3
  4. 由于 cur 指针到达了链表末尾,pre 指针现在指向结点 2,即要删除结点 3 的前一个结点。
  5. 删除结点 3,更新 pre.next 指针指向结点 4
  6. 返回虚拟头结点 dummy 的下一个结点,即链表的新头结点 1

结语

通过使用一次遍历,我们可以高效地从链表中删除倒数第 N 个结点。这种技术在各种链表操作中都非常有用,因为它可以帮助我们避免不必要的遍历和内存分配。理解这一技术将极大地提升你在链表编程方面的能力。