#82
中等
中频
迭代法删除排序链表中的重复元素 II
这是一道围绕链表、排序展开的高频练习。建议先掌握「迭代法」这套写法,再结合下方步骤讲解理解状态维护、边界处理和复杂度取舍。
链表
排序
题目分析
这道题表面上是在处理「删除排序链表中的重复元素 II」,但先要想清楚题目到底让你返回什么,以及过程中哪些约束必须一直满足。从题型上看,它主要在考 链表、排序 这些能力。这类题通常不难想到总体方向,真正容易乱的是遍历顺序、边界收缩和状态更新的先后关系。只有先把题目要求翻译成人话,后面的推荐代码才是在实现思路,而不是直接给答案。
接下来怎么看推荐代码: 带着这个理解再看推荐代码时,重点观察这条主线:用哑节点和前驱指针扫描链表,一旦发现重复值段,就整体跳过这一整段。
推荐代码
推荐解法:迭代法
时间复杂度: O(n)
空间复杂度: O(1)
核心思路: 用哑节点和前驱指针扫描链表,一旦发现重复值段,就整体跳过这一整段。
class Solution {
public ListNode deleteDuplicates(ListNode head) {
// 创建哑节点,方便处理头节点可能被删除的情况
ListNode dummy = new ListNode(0);
dummy.next = head;
// prev指向当前确定不重复的节点
ListNode prev = dummy;
// curr遍历链表
ListNode curr = head;
while (curr != null) {
// 检查当前节点是否有重复
boolean isDuplicate = false;
while (curr.next != null && curr.val == curr.next.val) {
isDuplicate = true;
curr = curr.next;
}
if (isDuplicate) {
// 如果有重复,跳过所有重复节点
prev.next = curr.next;
} else {
// 如果没有重复,prev移动到当前节点
prev = prev.next;
}
// curr继续前进
curr = curr.next;
}
return dummy.next;
}
}结构化讲解
面试时怎么讲
开场思路
这题我会用哑节点加双指针扫描链表,遇到重复段就整段删除。
核心过程
- 先让
prev指向哑节点,curr从头节点开始扫描。 - 如果当前值出现重复,就一路跳过这一整段相同值。
- 然后让
prev.next直接连到重复段之后。 - 如果当前值不重复,就把
prev和curr一起正常前进。
复杂度总结
时间复杂度 O(n),空间复杂度 O(1)。
面试补一句:这题最容易错的点,是“删重复段时 prev 不能前进”。
核心思路
这题不是“去重保留一个”,而是“重复值一个都不留”。关键在于识别连续重复段,并让前驱一次性绕过整段。
步骤讲解
1
先加哑节点统一头部处理
让 dummy.next = head,再用 prev 指向当前确定保留链表的尾部前驱。
为什么这样做:如果头节点本身处在重复段内,也能统一删除。
对应代码提示:ListNode dummy = new ListNode(0, head);
2
识别连续重复值段
当当前节点和后一个节点值相同,就持续向后移动直到跳过整段重复值。
为什么这样做:题目要求重复值全部删除,不能只删一个节点。
对应代码提示:while (curr.next != null && curr.val == curr.next.val) curr = curr.next;
3
重复段整体跳过,非重复节点正常前进
若发现重复段,就让 prev.next 直接连到重复段之后;否则同步推进 prev。
为什么这样做:这样才能同时兼顾删除整段和保留单个合法节点。
对应代码提示:prev.next = curr.next;
易错点
把题目当成普通去重链表
普通去重保留一个,这题是重复值全部删除,要求更严格。
正确理解:一旦某个值出现多次,这一整段节点都要跳过。
没用哑节点导致头部删除难处理
当开头就是重复段时,没有统一前驱很容易写出特判泥潭。
正确理解:先补
dummy 节点。跳过重复段后还推进了 prev
会错过新的连接位置,链表结构被破坏。
正确理解:删除重复段时只移动
curr,prev 留在原地负责重新接链。复杂度与适用判断
时间复杂度:O(n)
空间复杂度:O(1)
比其他方案更好在哪里:比借哈希表统计频次后再重建链表更省空间,也更符合有序链表特点。
适用判断:有序链表中只要需要按值分组处理,优先考虑双指针扫描连续段。
额外提醒
- 删除的是连续重复段,不是单个重复节点。
动画演示
如果你还没完全看懂,可以展开动画演示。
迭代法动画演示
想看这段解法是怎么一步步运行的,可以展开动画继续观察。
迭代法动画演示
想看这段解法是怎么一步步运行的,可以展开动画继续观察。
删除排序链表中的重复元素 II
当前步骤: 0 | 状态: 已暂停 | 链表长度: 0
dummy
→null
操作日志
算法说明
迭代算法:使用双指针遍历链表,检测并删除所有重复元素,只保留不重复的节点。
- 时间复杂度:O(n) - 只需遍历一次链表
- 空间复杂度:O(1) - 只使用常数级额外空间
- 关键思想:使用哑节点处理头节点可能被删除的情况
- 指针移动:prev指向当前确定不重复的节点,curr遍历链表
动画演示仅在桌面端提供,移动端请优先阅读推荐代码与结构化讲解。