LeetCode 83简单链表 · 删除
删除排序链表重复元素 图解题解
这道题到底在问什么
给定一个已升序排序的链表,删除所有重复出现的节点,使每个元素只出现一次,返回处理后的链表。
- 输入
- 1→1→2→2→3→4→4→5→6
- 输出
- 1→2→3→4→5→6
最优解:一步一步想明白
- 3「相同就跳过、不同才前进」——因为已排序,跳过的一定是和 cur 重复的那个。
- 4cur 停在头节点 1,先把它确认保留(标绿)。接下来反复比较 cur 和它后面的节点,决定「摘掉重复」还是「前进」。
- 5看 cur=1 和它后面的 next=1:两个都是 1,相等 → 这是重复,下一帧把 next 摘掉。
- 6执行 cur.next = cur.next.next:把重复节点 1 摘掉(变灰、两侧箭头断开 ·),cur 留在 1 不动,继续和再后面的节点比。
- 7看 cur=1 和它后面的 next=2:1 和 2 不相等 → cur 这个值处理完了,下一帧 cur 前进。
- 8执行 cur = cur.next:cur 前进一格到 2,开始处理这个新值。前面 已确认保留的节点变绿。
- 9看 cur=2 和它后面的 next=2:两个都是 2,相等 → 这是重复,下一帧把 next 摘掉。
- 10执行 cur.next = cur.next.next:把重复节点 2 摘掉(变灰、两侧箭头断开 ·),cur 留在 2 不动,继续和再后面的节点比。
- 11看 cur=2 和它后面的 next=3:2 和 3 不相等 → cur 这个值处理完了,下一帧 cur 前进。
- 12执行 cur = cur.next:cur 前进一格到 3,开始处理这个新值。前面 已确认保留的节点变绿。
- 13看 cur=3 和它后面的 next=4:3 和 4 不相等 → cur 这个值处理完了,下一帧 cur 前进。
- 14执行 cur = cur.next:cur 前进一格到 4,开始处理这个新值。前面 已确认保留的节点变绿。
- 15看 cur=4 和它后面的 next=4:两个都是 4,相等 → 这是重复,下一帧把 next 摘掉。
- 16执行 cur.next = cur.next.next:把重复节点 4 摘掉(变灰、两侧箭头断开 ·),cur 留在 4 不动,继续和再后面的节点比。
- 17看 cur=4 和它后面的 next=5:4 和 5 不相等 → cur 这个值处理完了,下一帧 cur 前进。
- 18执行 cur = cur.next:cur 前进一格到 5,开始处理这个新值。前面 已确认保留的节点变绿。
- 19看 cur=5 和它后面的 next=6:5 和 6 不相等 → cur 这个值处理完了,下一帧 cur 前进。
- 20执行 cur = cur.next:cur 前进一格到 6,开始处理这个新值。前面 已确认保留的节点变绿。
- 21cur 走到最后一个存活节点 6,后面没有节点了,结束。灰掉的都是重复副本,剩下的绿色节点 1→2→3→4→5→6 就是答案,每个值只出现一次。
⚠️ 容易写错的地方
✗ 错:摘掉节点后立刻 cur = cur.next
✓ 对:摘掉重复后 cur 必须留在原地
后面可能还有连续重复(如 2→2→2),不留原地会漏删
✗ 错:循环条件只写 while cur
✓ 对:必须 while cur && cur.next
要访问 cur.next.val,cur.next 为空会越界/空指针
✗ 错:以为要新建头/哑节点
✓ 对:本题头节点一定保留,直接原地改即可
每个值至少留一个,头节点的值天然保留
完整代码(Python / C++ / Java)
Python
def deleteDuplicates(head):
cur = head
while cur and cur.next:
if cur.next.val == cur.val:
cur.next = cur.next.next # 摘掉重复,cur 不动
else:
cur = cur.next # 不同才前进
return headC++
ListNode* deleteDuplicates(ListNode* head){
ListNode* cur = head;
while (cur && cur->next) {
if (cur->next->val == cur->val)
cur->next = cur->next->next;
else
cur = cur->next;
}
return head;
}Java
public ListNode deleteDuplicates(ListNode head) {
ListNode cur = head;
while (cur != null && cur.next != null) {
if (cur.next.val == cur.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head;
}复杂度
时间
O(n)
cur 把每个节点最多经过一遍
空间
O(1)
只用一个指针,原地改 next,不开额外结构
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 删除排序链表重复元素 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
如果要求重复的全部删掉、一个都不留(LC82)怎么改?+
需要哑节点 dummy 接在头前,用 prev 指向「已确认不重复段」的尾部;遇到一段重复时整段跳过,prev.next 直接接到该段之后。
链表没排序还能 O(n) 去重吗?+
可以用哈希集合记录见过的值,遇到重复就跳过;时间 O(n)、空间 O(n)。本题因已排序才省下这份空间。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 删除排序链表重复元素 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。