【LeetCode】82. 删除排序链表中的重复元素 II
算法思路
核心目标:删除所有重复元素,只保留唯一值。关键点在于:
- 哑节点预处理:避免处理头节点被删除的特殊情况
- 双指针探测:用前驱指针
pre维护有效链表,当前指针cur探测重复区域 - 重复区间检测:当发现
cur与后续节点重复时,跳过整个重复区间
实现代码
type ListNode struct { Val int Next *ListNode } func deleteDuplicates(head *ListNode) *ListNode { // 创建哑节点,处理头节点可能被删除的情况 dummy := &ListNode{Next: head} pre := dummy cur := head for cur != nil { // 检测重复区域:当前节点与下一节点值相同 if cur.Next != nil && cur.Val == cur.Next.Val { // 找到重复区域末尾 duplicateVal := cur.Val for cur != nil && cur.Val == duplicateVal { cur = cur.Next } // 跳过整个重复区域 pre.Next = cur } else { // 非重复节点正常移动指针 pre = cur cur = cur.Next } } return dummy.Next }
关键逻辑解析
- 哑节点初始化:
dummy.Next = head创建虚拟头节点,统一处理逻辑(包括头节点被删除的情况) - 重复区域探测:当发现
cur.Val == cur.Next.Val时进入重复处理逻辑:- 记录当前重复值
duplicateVal - 循环移动
cur直到脱离重复区域 - 通过
pre.Next = cur直接跳过重复区间
- 记录当前重复值
- 非重复处理:当没有重复时,正常推进
pre和cur指针
复杂度分析
- 时间复杂度:O(n),链表每个节点最多被访问两次
- 空间复杂度:O(1),仅使用固定数量指针变量
测试用例验证
func main() { // 示例1:1->2->3->3->4->4->5 → 1->2->5 n1 := &ListNode{1, &ListNode{2, &ListNode{3, &ListNode{3, &ListNode{4, &ListNode{4, &ListNode{5, nil}}}}}}} printList(deleteDuplicates(n1)) // 1->2->5->nil // 示例2:1->1->1->2->3 → 2->3 n2 := &ListNode{1, &ListNode{1, &ListNode{1, &ListNode{2, &ListNode{3, nil}}}}} printList(deleteDuplicates(n2)) // 2->3->nil }
扩展优化
- 早期终止:当剩余节点数不足2个时可提前终止循环(
cur.Next == nil时直接退出) - 内存回收:在跳过重复节点时,可显式断开引用帮助GC回收(但Go的GC会自动处理)
- 并发安全:若需线程安全操作,需添加互斥锁(但链表操作通常不涉及并发场景)

浙公网安备 33010602011771号