LeetCode 83: Remove Duplicates from Sorted List (Single-Pass Pointer Compression)
LeetCode 83Linked ListTwo PointersInterviewToday we solve LeetCode 83 - Remove Duplicates from Sorted List.
Source: https://leetcode.com/problems/remove-duplicates-from-sorted-list/
English
Problem Summary
Given the head of a sorted linked list, delete duplicates so each value appears only once, and return the deduplicated list.
Key Insight
Because the list is sorted, duplicates are adjacent. We keep a pointer cur and compress each equal-value run by redirecting cur.next to the first node with a different value.
Brute Force and Limitations
You can copy unique values into an array/set and rebuild a new list. It works, but wastes memory and ignores the in-place linked-list advantage.
Optimal Algorithm Steps
1) Let cur = head.
2) While cur and cur.next exist:
- If cur.val == cur.next.val, remove duplicate by cur.next = cur.next.next.
- Else move forward: cur = cur.next.
3) Return head.
Complexity Analysis
Time: O(n) — each node is visited at most once after rewiring.
Space: O(1).
Common Pitfalls
- Advancing cur immediately after deletion and accidentally skipping checks for triple duplicates.
- Confusing this problem with LeetCode 82 (which removes all duplicated values entirely).
- Rebuilding a new list unnecessarily.
Reference Implementations (Java / Go / C++ / Python / JavaScript)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode cur = head;
while (cur != null && cur.next != null) {
if (cur.val == cur.next.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head;
}
}/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func deleteDuplicates(head *ListNode) *ListNode {
cur := head
for cur != nil && cur.Next != nil {
if cur.Val == cur.Next.Val {
cur.Next = cur.Next.Next
} else {
cur = cur.Next
}
}
return head
}/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* cur = head;
while (cur && cur->next) {
if (cur->val == cur->next->val) {
cur->next = cur->next->next;
} else {
cur = cur->next;
}
}
return head;
}
};# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur = head
while cur and cur.next:
if cur.val == cur.next.val:
cur.next = cur.next.next
else:
cur = cur.next
return head/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
var deleteDuplicates = function(head) {
let cur = head;
while (cur && cur.next) {
if (cur.val === cur.next.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head;
};中文
题目概述
给定一个已排序链表,删除重复元素,使每个值只出现一次,并返回处理后的链表。
核心思路
因为链表有序,重复值一定连续。维护指针 cur:如果 cur 和 cur.next 相同,就把 cur.next 跳过去;否则 cur 正常后移。
暴力解法与不足
可以先收集不重复值再重建链表,但这会引入额外空间,且没有利用“原地修改链表”的优势。
最优算法步骤
1)初始化 cur = head。
2)当 cur 与 cur.next 都存在时循环:
- 若两者值相等,执行 cur.next = cur.next.next 删除重复节点。
- 否则 cur = cur.next。
3)返回 head。
复杂度分析
时间复杂度 O(n);空间复杂度 O(1)。
常见陷阱
- 删除一个重复节点后立刻后移,可能漏删后续重复值。
- 把本题和 LeetCode 82 混淆(82 要删除所有重复值,只保留只出现一次的节点)。
- 不必要地新建链表,增加空间开销。
多语言参考实现(Java / Go / C++ / Python / JavaScript)
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode deleteDuplicates(ListNode head) {
ListNode cur = head;
while (cur != null && cur.next != null) {
if (cur.val == cur.next.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head;
}
}/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func deleteDuplicates(head *ListNode) *ListNode {
cur := head
for cur != nil && cur.Next != nil {
if cur.Val == cur.Next.Val {
cur.Next = cur.Next.Next
} else {
cur = cur.Next
}
}
return head
}/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode* cur = head;
while (cur && cur->next) {
if (cur->val == cur->next->val) {
cur->next = cur->next->next;
} else {
cur = cur->next;
}
}
return head;
}
};# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur = head
while cur and cur.next:
if cur.val == cur.next.val:
cur.next = cur.next.next
else:
cur = cur.next
return head/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
var deleteDuplicates = function(head) {
let cur = head;
while (cur && cur.next) {
if (cur.val === cur.next.val) {
cur.next = cur.next.next;
} else {
cur = cur.next;
}
}
return head;
};
Comments