返回

从排序链表中移除重复元素 II:Python 指南

前端

导言

链表是一种广泛使用的数据结构,由一系列按顺序连接的节点组成。在某些情况下,链表中可能包含重复的元素。在这些情况下,删除重复元素以维护数据的完整性和一致性至关重要。

方法

哑结点法

哑结点是一种虚拟节点,它被添加到链表的开头,以简化对边界条件的处理。

  1. 创建一个哑结点,并将它的 next 指针指向头结点。
  2. 初始化两个指针:prev 指向哑结点,curr 指向头结点。
  3. 遍历链表,直到 curr 为空:
    • 如果 curr.valprev.val 相等,则将 prev.next 指向 curr.next,跳过 curr
    • 否则,将 prev 移动到 curr
  4. 返回哑结点的 next 指针,因为它现在指向去除了重复元素的链表。
def remove_duplicates_with_dummy(head):
    dummy = ListNode(0, head)
    prev = dummy
    curr = head

    while curr:
        if curr.val == prev.val:
            prev.next = curr.next
        else:
            prev = curr
        curr = curr.next

    return dummy.next

迭代法

迭代法类似于哑结点法,但不需要创建一个额外的哑结点。

  1. 初始化两个指针:prev 指向空,curr 指向头结点。
  2. 遍历链表,直到 curr 为空:
    • 如果 prev 为空或 curr.valprev.val 相等,则跳过 curr
    • 否则,将 prev 移动到 curr
  3. 返回 prev 指针,因为它现在指向去除了重复元素的链表。
def remove_duplicates_iteratively(head):
    prev = None
    curr = head

    while curr:
        if prev is None or curr.val != prev.val:
            prev = curr
        else:
            prev.next = curr.next
        curr = curr.next

    return prev

递归法

递归法使用分而治之的方法来解决问题。

  1. 如果链表为空或只有一个元素,则返回链表。
  2. 否则,检查头结点的值是否与下一个元素的值相等:
    • 如果相等,则返回删除头结点的剩余链表。
    • 如果不相等,则返回头结点链接到删除下一个元素后的剩余链表。
def remove_duplicates_recursively(head):
    if not head or not head.next:
        return head

    if head.val == head.next.val:
        return remove_duplicates_recursively(head.next)
    else:
        head.next = remove_duplicates_recursively(head.next)
        return head

复杂度分析

时间复杂度:对于所有三种方法,时间复杂度都为 O(n),其中 n 是链表中的节点数。这是因为它们都遍历了整个链表一次。

空间复杂度:哑结点法需要 O(1) 的额外空间,而迭代法和递归法不需要额外的空间。

结论

我们讨论了使用 Python 从排序链表中删除重复元素的几种方法。这些方法在时间和空间复杂度上各不相同,你可以根据自己的具体需求选择最适合你的方法。理解这些算法对于处理需要从链表中删除重复元素的实际问题非常重要。