返回

使用python优雅地删除链表倒数第n个结点

前端

征服链表:删除倒数第 N 个结点

在处理链表时,删除倒数第 N 个结点是一个常见且至关重要的任务。乍一看,这似乎有点棘手,但凭借正确的策略,我们可以轻松解决这个问题。在这篇文章中,我们将深入探讨三种有效的方法来删除链表的倒数第 N 个结点,并用代码示例进行说明。

方法一:递归的力量

递归 是一种解决问题的强大技术,它可以通过不断将问题分解成更小的子问题来解决更复杂的问题。对于链表来说,递归可以用来从倒数第 N 个结点处轻松删除结点。

思路如下:

  • 定义一个递归函数 remove_nth_from_end(head, n),其中 head 是链表的头结点,n 是要删除的倒数第 N 个结点。
  • 在递归函数中,我们首先检查 n 是否为 0。如果 n 为 0,这意味着我们已经找到了要删除的结点,将其从链表中删除并返回修改后的链表。
  • 如果 n 不为 0,这意味着我们还没有找到要删除的结点。我们递归调用 remove_nth_from_end(head.next, n - 1),并在返回时更新链表。

代码示例:

def remove_nth_from_end(head, n):
    if n == 0:
        return head.next
    else:
        head.next = remove_nth_from_end(head.next, n - 1)
        return head

方法二:迭代之美

迭代 是一种逐个元素处理链表的简单而高效的方法。对于倒数第 N 个结点的删除,我们可以使用迭代来实现。

思路如下:

  • 设置两个指针 slowfast,都指向链表的头结点。
  • fast 指针向前移动 N 个结点。
  • fast 指针到达链表的末尾时,slow 指针将指向倒数第 N 个结点。
  • 移除倒数第 N 个结点。

代码示例:

def remove_nth_from_end(head, n):
    slow = head
    fast = head
    for i in range(n):
        fast = fast.next
    while fast.next:
        slow = slow.next
        fast = fast.next
    slow.next = slow.next.next
    return head

方法三:一趟扫描的优雅

一趟扫描 是一种在单个遍历中完成任务的有效方法。对于链表,我们可以使用一趟扫描来删除倒数第 N 个结点。

思路如下:

  • 设置两个指针 dummyslow,都指向链表的头结点。
  • 创建一个虚拟结点 dummy,该结点指向链表的头结点。
  • slow 指针向前移动 N 个结点。
  • slow 指针到达链表的末尾时,dummy 指针将指向倒数第 N 个结点的上一个结点。
  • 移除倒数第 N 个结点。

代码示例:

def remove_nth_from_end(head, n):
    dummy = ListNode(0)
    dummy.next = head
    slow = dummy
    for i in range(n):
        slow = slow.next
    while slow.next:
        slow = slow.next
        head = head.next
    slow.next = slow.next.next
    return dummy.next

常见问题解答

1. 这三种方法有什么区别?

  • 递归方法在效率方面不如其他两种方法。
  • 迭代方法和一趟扫描方法效率更高,但一趟扫描方法只需要遍历链表一次,因此总体上效率更高。

2. 如何选择使用哪种方法?

  • 如果链表较小,则递归方法可能是最简单的选择。
  • 如果链表较大,则迭代方法或一趟扫描方法更有效率。
  • 如果需要在不修改原始链表的情况下进行删除,则可以考虑一趟扫描方法。

3. 是否可以删除链表中的任何结点?

  • 是的,这三种方法都可以用来删除链表中的任何结点,包括头结点和尾结点。

4. 如果 N 超过链表的长度会怎样?

  • 如果 N 超过链表的长度,这三种方法都会抛出异常或返回空链表。

5. 是否可以删除重复的倒数第 N 个结点?

  • 这三种方法都不支持删除重复的倒数第 N 个结点。