【算法--链表】82.删除排序链表中的重复元素 II--通俗讲解
一、题目是啥?一句话说清
给你一个已经排序的链表,删除所有重复数字的节点(包括本身),只留下不同的数字,并返回处理后的链表。
示例:
- 输入:1 → 1 → 2 → 3 → 3
- 输出:2(因为所有1和3都被删除,只留下2)
二、解题核心
使用虚拟头节点简化操作,遍历链表,对于每个节点,检查其后是否有重复节点,如果有则跳过整个重复序列。 这就像处理一排已经排序的队伍,如果发现连续多个人身高相同,就让所有这些人都离开队伍。
三、关键在哪里?(3个核心点)
想理解并解决这道题,必须抓住以下三个关键点:
1. 虚拟头节点(Dummy Node)的使用
- 是什么:在原始链表前添加一个不存储实际数据的节点。
- 为什么重要:因为头节点可能被删除(如示例中头节点1被删除),使用虚拟头节点可以避免单独处理头节点变化的情况。
2. 跳过整个重复序列
- 是什么:当发现重复时,不是只跳过下一个节点,而是找到重复序列的结束位置,然后一次性跳过所有重复节点。
- 为什么重要:因为题目要求删除所有重复数字的节点,而不是保留一个。
3. 指针操作的安全性
- 是什么:在遍历链表时,需要确保指针不为空,避免空指针异常。
- 为什么重要:因为可能操作到链表的末尾,需要谨慎检查指针的next属性。
四、看图理解流程(通俗理解版本)
让我们用链表 1 → 1 → 2 → 3 → 3 的例子来可视化过程:
-
初始化:
- 创建虚拟头节点
dummy
,其 next 指向头节点 1。 - 设置当前指针
curr
指向dummy
。 - 初始状态:dummy → 1 → 1 → 2 → 3 → 3
- 创建虚拟头节点
-
第一轮检查:
curr
指向 dummy,检查curr.next
(1) 和curr.next.next
(1) 的值是否相等。- 相等,说明有重复,需要删除所有值为1的节点。
- 找到第一个值不为1的节点(节点2)。
- 将
curr.next
指向节点2(跳过所有1)。 - 链表状态:dummy → 2 → 3 → 3
curr
仍然指向 dummy(因为可能新的开头还有重复)。
-
第二轮检查:
curr
指向 dummy,检查curr.next
(2) 和curr.next.next
(3) 的值是否相等。- 不相等,说明没有重复,移动
curr
到curr.next
(指向2)。 - 链表状态:dummy → 2 → 3 → 3
-
第三轮检查:
curr
指向2,检查curr.next
(3) 和curr.next.next
(3) 的值是否相等。- 相等,说明有重复,需要删除所有值为3的节点。
- 找到第一个值不为3的节点(null)。
- 将
curr.next
指向 null(跳过所有3)。 - 链表状态:dummy → 2
-
结束:
- 返回
dummy.next
,即节点2。
- 返回
五、C++ 代码实现(附详细注释)
#include <iostream>
using namespace std;// 链表节点定义
struct ListNode {int v