Skip to content
← All posts

Remove Duplicates from Sorted List: Keep One of Each

4 min read
leetcodeproblemeasylinked-lists

Remove Duplicates from Sorted List is LeetCode problem 83. You are given the head of a sorted linked list. Delete all duplicate nodes so that each value appears only once. Return the modified list, still sorted.

Example: 1 -> 1 -> 2 -> null becomes 1 -> 2 -> null. Another: 1 -> 1 -> 2 -> 3 -> 3 -> null becomes 1 -> 2 -> 3 -> null.

before11233nullafter123null
Duplicate nodes (red) are removed. Each value appears exactly once in the result.

Because the list is already sorted, all duplicates are adjacent. That one fact makes this problem much simpler than deduplicating an unsorted collection. You do not need a hash set. You do not need to sort anything. You just need to walk forward and skip nodes that repeat the current value.

The approach

Use a single pointer called curr that starts at the head. At each step, compare curr.val with curr.next.val:

  • If they match, the next node is a duplicate. Skip it by setting curr.next = curr.next.next. Do not advance curr yet, because the new curr.next might also be a duplicate.
  • If they differ, the next node is a new value. Advance curr to curr.next.

Keep going until curr.next is null. Then return the head.

That is the entire algorithm. One pointer, one comparison per iteration, no extra memory.

Visual walkthrough

Trace through the list 1 -> 1 -> 2 -> 3 -> 3 -> null. Watch the curr pointer (amber) as it moves through the list, skipping duplicate nodes (red) along the way.

Start: curr = node 1

11233nullcurr

curr starts at the head. curr.val is 1, and curr.next.val is also 1. Duplicate found.

Step 1: curr.val == curr.next.val (1 == 1). Skip the duplicate.

11233nullcurr

Set curr.next = curr.next.next, bypassing the duplicate. curr stays at node 1.

Step 2: curr.val != curr.next.val (1 != 2). Move curr forward.

1233nullcurr

No duplicate here, so advance curr to node 2. Node 1 is finalized.

Step 3: curr.val != curr.next.val (2 != 3). Move curr forward.

1233nullcurr

Values differ, so advance curr to node 3. Node 2 is finalized.

Step 4: curr.val == curr.next.val (3 == 3). Skip the duplicate.

1233nullcurr

Set curr.next = curr.next.next (null). The duplicate 3 is removed. curr.next is now null.

Done: curr.next is null. Loop ends.

123nullcurr

All duplicates removed. Return head. The list is now 1 -> 2 -> 3 -> null.

Notice that curr only advances when the next value is different. When a duplicate is found, curr stays put and the duplicate gets bypassed. This ensures you catch consecutive runs of the same value, no matter how long they are.

Python solution

def deleteDuplicates(head):
    curr = head

    while curr and curr.next:
        if curr.val == curr.next.val:
            curr.next = curr.next.next
        else:
            curr = curr.next

    return head

The logic mirrors the walkthrough exactly. When curr.val matches curr.next.val, you splice out the duplicate by rewiring the pointer. Otherwise, you move forward. The loop exits when curr is null or curr.next is null, meaning you have reached the end.

Complexity analysis

Time: O(n). You visit each node at most once. Even when you skip a duplicate, that node is never visited again. The total number of pointer operations across all iterations is at most n.

Space: O(1). You only use one pointer variable. The deduplication happens in-place by rewiring existing nodes. No extra data structures are needed.

The building blocks

This problem is built from one core building block:

In-place linked list deduplication. You walk a sorted list with a single pointer, comparing each node to its neighbor. When they match, you splice out the duplicate by skipping the next pointer over it. When they differ, you advance.

This technique generalizes naturally:

  • Remove Duplicates from Sorted List II (LeetCode 82) removes all nodes that have duplicates, keeping only values that appear exactly once. Same traversal pattern, but you need a prev pointer to handle removing the first occurrence too.
  • Remove Duplicates from Sorted Array (LeetCode 26) applies the same idea to arrays with a read/write pointer approach instead of pointer rewiring.
  • Any problem that asks you to "remove" elements from a linked list in-place uses the same curr.next = curr.next.next splice operation.

Once this pattern is muscle memory, any linked list removal problem becomes a variation rather than a new puzzle.

Edge cases

  • Empty list (head is null). The while condition fails immediately. Return null.
  • Single node. curr.next is null from the start. The loop never runs. Return the single node unchanged.
  • All nodes have the same value (e.g., 1 -> 1 -> 1 -> 1). Each iteration finds a duplicate and splices it out. curr never advances. You end up with a single node.
  • No duplicates at all (e.g., 1 -> 2 -> 3 -> 4). Each iteration finds different values and advances curr. No splicing happens. The list is returned as-is.

A common mistake is advancing curr after removing a duplicate. If you always do curr = curr.next, you will skip the comparison between the current node and its new neighbor, potentially missing consecutive duplicates like 1 -> 1 -> 1.

From understanding to recall

This is a five-line solution. You will read it once and think you have it memorized. But the subtlety is in knowing when to advance curr and when to stay put. Under interview pressure, that if/else distinction is exactly the kind of detail that slips away.

The fix is not to read the solution more carefully. It is to type it from scratch, repeatedly, until the branching logic is automatic. Spaced repetition turns a solution you understand into a solution you can reproduce without hesitation.

Related posts

  • Reverse Linked List - Another fundamental linked list operation that tests whether you truly understand pointer manipulation
  • Linked List Cycle - A different single-pass linked list traversal where the key insight is how you move your pointers