返回

LeetCode 83:巧用哈希表优化,高效剔除链表重复元素

后端

删除排序链表中的重复元素:三种优化方法

什么是删除排序链表中的重复元素问题?

给定一个已排序的链表,删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。

暴力法:双指针法

暴力法使用两个指针来解决这个问题:

  • 慢指针 (slow) :指向当前节点。
  • 快指针 (fast) :指向下一个节点。

算法步骤:

  1. 初始化 slow 和 fast 指针为头节点。
  2. 遍历链表,如果 slow 指向的节点值与 fast 指向的节点值相同,则跳过 fast 指向的节点。
  3. 如果 slow 指向的节点值与 fast 指向的节点值不同,则将 slow 指向下一个节点,并继续步骤 2。

哈希表优化

哈希表优化通过使用哈希表存储已遇到的节点值来提高效率:

  • 创建一个哈希表来存储已遇到的节点值。
  • 遍历链表,如果当前节点的值已在哈希表中,则跳过该节点。
  • 如果当前节点的值不在哈希表中,则将其添加到哈希表中,并将该节点的下一个节点设置为下一个节点。

空间优化

空间优化进一步减少哈希表的使用:

  • 将链表分成若干组,每组中的元素都是相同的。
  • 存储每个组的第一个元素。
  • 将这些组连接起来,即可得到最终的链表。

代码示例

# 暴力法:双指针法
def deleteDuplicates_BF(head):
    if head is None:
        return None

    slow = head
    fast = head.next

    while fast is not None:
        if slow.val == fast.val:
            fast = fast.next
        else:
            slow.next = fast
            slow = slow.next
            fast = fast.next

    slow.next = None

    return head


# 哈希表优化
def deleteDuplicates_HT(head):
    if head is None:
        return None

    hash_table = set()
    slow = head
    fast = head.next

    while fast is not None:
        if slow.val in hash_table:
            fast = fast.next
        else:
            hash_table.add(slow.val)
            slow.next = fast
            slow = slow.next
            fast = fast.next

    slow.next = None

    return head


# 空间优化
def deleteDuplicates_SO(head):
    if head is None:
        return None

    dummy = ListNode(0, head)
    prev = dummy
    curr = head

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

    prev.next = None

    return dummy.next

总结

我们探讨了删除排序链表中重复元素的三种优化方法:暴力法、哈希表优化和空间优化。这些方法都在效率和空间使用方面提供了不同的权衡。选择最合适的方法取决于特定问题和可用资源。

常见问题解答

Q1:哪种方法最有效率?
A1:空间优化通常是最有效率的,因为它不需要使用额外的空间。

Q2:哪种方法最易于实现?
A2:暴力法是最易于实现的,因为它不需要任何特殊的数据结构或技术。

Q3:什么时候应该使用暴力法?
A3:当链表较小或效率不是主要问题时,可以使用暴力法。

Q4:什么时候应该使用哈希表优化?
A4:当链表较大且需要提高效率时,可以使用哈希表优化。

Q5:什么时候应该使用空间优化?
A5:当链表非常大或可用空间有限时,可以使用空间优化。