链表去重:如何精准删除排序链表中的重复元素?

链表去重:如何精准删除排序链表中的重复元素?

在算法世界里,链表是一种常见的数据结构,它灵活、动态,适合插入和删除操作。然而,处理排序链表中的重复元素,却是一个略显棘手的问题——既要确保删除掉所有重复值,又要维持链表的整体结构。这就涉及到了条件删除的核心逻辑。今天,我们就来拆解**“删除排序链表中的重复元素 II”**这个问题,看看如何高效、精准地实现它。


1. 题目解析:究竟该删什么?

题目要求:

  • 给定一个 升序排序 的链表。
  • 需要删除所有重复出现的元素,仅保留未重复的元素

示例:

输入: 1 -> 2 -> 3 -> 3 -> 4 -> 4 -> 5
输出: 1 -> 2 -> 5

可以看到,所有重复的 3 和 4 都被清理掉,而非简单地删除重复项后保留一个。这意味着,我们必须精准识别和剔除重复值


2. 解决思路:双指针遍历链表

由于链表已经有序,我们可以利用双指针遍历的方式:

  1. 使用一个虚拟头结点(dummy),方便处理链表头部的删除操作。

  2. 采用前置指针(prev)和当前指针(current)

    • prev 指向上一层有效节点;
    • current 负责扫描当前元素,检测是否有重复。
  3. 发现重复元素时,跳过整个重复区间

    • 如果 current 指向的元素有多个相邻重复值,则prev 直接跳过这些值,指向下一个不同的元素。
    • 直到遍历结束,返回新的链表。

3. 代码实现:Python版

让我们用 Python 实现这个逻辑:

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def deleteDuplicates(head):
    """
    删除排序链表中的重复元素(只保留未重复的元素)
    """
    dummy = ListNode(0)  # 虚拟头结点,方便处理头部删除问题
    dummy.next = head
    prev = dummy  # 前置指针
    current = head  # 当前指针

    while current:
        # 检测是否有重复元素
        if current.next and current.val == current.next.val:
            # 跳过所有重复的元素
            while current.next and current.val == current.next.val:
                current = current.next
            prev.next = current.next  # 彻底跳过该元素
        else:
            prev = prev.next  # 正常移动前置指针
        current = current.next  # 继续遍历

    return dummy.next  # 返回处理后的链表

代码解析:

  • 虚拟头结点 dummy:避免删除头部元素时的特殊处理。
  • prev.next = current.next:当 current 指向重复元素时,跳过整个区间。
  • 外层 while current:确保链表遍历到底。

4. 代码示例运行

假设我们的输入链表是:

1 -> 2 -> 3 -> 3 -> 4 -> 4 -> 5

用下面的方式测试代码:

# 构建测试链表
head = ListNode(1, ListNode(2, ListNode(3, ListNode(3, ListNode(4, ListNode(4, ListNode(5)))))))

# 运行去重函数
result = deleteDuplicates(head)

# 打印结果
while result:
    print(result.val, end=" -> ")
    result = result.next

输出结果:

1 -> 2 -> 5 ->

成功删除所有重复值,仅保留唯一的数值。


5. 复杂度分析:性能如何?

  • 时间复杂度:O(n),我们只需遍历链表一次。
  • 空间复杂度:O(1),不需要额外的存储,只使用几个辅助指针。

这意味着,该方法在大规模链表数据下依然高效,不会占用太多资源。


6. 扩展优化:如何处理未排序链表?

如果链表是无序的,那么上述方法就不适用了。我们可以先对链表排序,再采用相同的逻辑删除重复元素:

def sort_linked_list(head):
    """
    对链表排序(使用归并排序)
    """
    if not head or not head.next:
        return head
    
    # 快慢指针拆分链表
    slow, fast = head, head.next
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next

    mid = slow.next
    slow.next = None

    # 递归排序
    left = sort_linked_list(head)
    right = sort_linked_list(mid)

    return merge_sorted_list(left, right)

def merge_sorted_list(l1, l2):
    """
    归并两个已排序链表
    """
    dummy = ListNode(0)
    tail = dummy
    while l1 and l2:
        if l1.val < l2.val:
            tail.next, l1 = l1, l1.next
        else:
            tail.next, l2 = l2, l2.next
        tail = tail.next

    tail.next = l1 or l2
    return dummy.next

先排序,再用双指针删除重复值,这样就能兼容无序链表


7. 总结

🔹 核心思路:利用双指针遍历,精准跳过重复区间。
🔹 代码实现:使用 dummy 虚拟头结点,确保边界处理统一。
🔹 性能分析:O(n) 时间复杂度 + O(1) 空间复杂度,高效稳定。
🔹 扩展优化:如果链表是无序的,先排序再删除重复元素。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Echo_Wish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值