Remove Duplicates Sorted Array: The Simplest Two-Pointer Problem
Remove Duplicates from Sorted Array (LeetCode 26) is often the very first two-pointer problem you encounter on the NeetCode roadmap. It asks a deceptively simple question: given a sorted integer array, remove the duplicates in place and return the new length.
What makes this problem special is not its difficulty — it is rated Easy — but that it introduces the slow/fast two-pointer partition pattern. This exact technique reappears in Move Zeroes (#283), Sort Colors (#75), and dozens of other array manipulation problems.
If you master the mental model here, you unlock a template that transfers directly to harder problems. Let us break it down step by step.
Understanding the Problem
You are given an integer array nums sorted in non-decreasing order. Your task is to remove duplicates in place so that each unique element appears only once. Return the number of unique elements, k.
The first k elements of nums must contain the unique values in their original order. Elements beyond index k do not matter — the judge only checks the first k slots.
For example, given nums = [1,1,2], you should return k = 2 and modify nums so the first two elements are [1,2]. Given nums = [0,0,1,1,1,2,2,3,3,4], you return k = 5 with the first five elements being [0,1,2,3,4].
- Input: a sorted integer array (non-decreasing order)
- Output: the count of unique elements (k)
- Constraint: modify the array in place — no extra array allowed
- Elements after index k-1 are ignored by the judge
NeetCode Roadmap
Remove Duplicates from Sorted Array (#26) is one of the first Easy problems in the NeetCode roadmap — it teaches the exact two-pointer technique used in Move Zeroes and Sort Colors.
Two Pointer Solution for Remove Duplicates
The key insight is to use two pointers moving in the same direction. The slow pointer marks the position of the last unique element written. The fast pointer scans ahead looking for the next unique value.
Initialize slow at index 0. Start fast at index 1. Compare nums[fast] with nums[slow]. If they are different, increment slow and copy nums[fast] to nums[slow]. If they are the same, just advance fast.
When fast reaches the end of the array, slow + 1 is your answer — the count of unique elements. Every unique value has been copied into the first slow + 1 positions.
This runs in O(n) time with O(1) extra space. You scan the array once and write each unique element exactly once. No hash set, no extra allocation, no sorting — just two index variables.
- 1Set slow = 0, fast = 1
- 2While fast < nums.length: if nums[fast] != nums[slow], increment slow and set nums[slow] = nums[fast]
- 3Advance fast by 1 each iteration regardless
- 4Return slow + 1 as the count of unique elements
Why Sorted Order Matters for Remove Duplicates
The entire approach depends on one critical property: in a sorted array, duplicate values are always adjacent. That means you only need to compare nums[fast] with nums[slow] to detect a new unique value. No hash set is needed.
If the array were unsorted, duplicates could appear anywhere. You would need a hash set to track which values you have already seen, which costs O(n) extra space. The sorted constraint is what makes the O(1) space solution possible.
This is a pattern you will see again and again in interview problems. Always check whether the input is sorted before choosing your approach. Sorted input often unlocks two-pointer and binary search solutions that are impossible with unsorted data.
Sorted Input Required
This only works on SORTED arrays — if the array is unsorted, duplicates aren't adjacent and you'd need a hash set. Always check if the input is sorted before applying this pattern.
Visual Walkthrough of Remove Duplicates
Let us trace through the two examples to see exactly how slow and fast pointers move.
Example 1: nums = [1,1,2]. Start with slow=0, fast=1. nums[1]=1 equals nums[0]=1, so skip. fast=2: nums[2]=2 differs from nums[0]=1, so slow becomes 1 and nums[1] = 2. Array is now [1,2,1]. Return slow+1 = 2.
Example 2: nums = [0,0,1,1,1,2,2,3,3,4]. Slow starts at 0. Fast scans: 0 is duplicate, skip. 1 is new — slow=1, write 1. Two more 1s are duplicates, skip. 2 is new — slow=2, write 2. Another 2, skip. 3 is new — slow=3, write 3. Another 3, skip. 4 is new — slow=4, write 4. Return 5.
Notice how slow only moves forward when a genuinely new value is found. It acts as a write pointer, always pointing to the position where the next unique element should go.
- [1,1,2] -> [1,2,_] return 2
- [0,0,1,1,1,2,2,3,3,4] -> [0,1,2,3,4,...] return 5
Edge Cases to Consider
Empty array: if nums.length is 0, return 0. There are no elements to process. Most two-pointer solutions need this guard at the top.
Single element: if nums.length is 1, return 1. A single element is always unique. The slow pointer never moves because fast starts out of bounds.
All elements identical: nums = [5,5,5,5]. Fast scans every element and never finds a difference. Slow stays at 0. Return 1.
No duplicates: nums = [1,2,3,4,5]. Every comparison finds a new value. Slow advances every time, keeping pace with fast. Return 5 — the full array length.
- Empty array -> return 0
- Single element -> return 1
- All same values -> return 1
- Already unique -> return original length
Pro Tip
The slow pointer always points to the last unique element. When fast finds something different, increment slow and copy. One pass, no extra space, clean code.
What Remove Duplicates Teaches You
LeetCode 26 is your entry point into the same-direction two-pointer partition pattern. The slow pointer partitions the array into a "processed" region (unique values) and an "unprocessed" region (everything else). The fast pointer scans the unprocessed region.
This exact pattern appears in Move Zeroes (#283), where slow marks the boundary of non-zero elements. It shows up in Sort Colors (#75), where you partition by value. It even extends to Remove Element (#27) and Remove Duplicates II (#80).
Once you internalize the mental model — slow holds position, fast scans, copy when the condition is met — you can solve an entire family of array partition problems. Practice this pattern with YeetCode flashcards to build the recall that makes it automatic during interviews.