Remove Element: The Simplest In-Place Partition
Remove Element (#27) is one of the first problems most people encounter on LeetCode, and for good reason. It distills the core idea behind in-place array modification into its simplest possible form: given an array and a value, remove all instances of that value and return the new length.
If you have solved Remove Duplicates from Sorted Array (#26) or Move Zeroes (#283), you already know the underlying technique. The remove element leetcode pattern is the same two-pointer partition — a slow pointer marks where to write, a fast pointer scans ahead, and you copy or skip elements based on a single condition.
This walkthrough covers the standard two-pointer solution, a swap-with-end variant for when the target value is rare, a visual step-by-step trace, and the edge cases that trip people up in interviews.
Understanding the Problem
You are given an integer array nums and an integer val. Remove all occurrences of val in nums in-place. The order of the elements may be changed. Then return the number of elements in nums which are not equal to val.
The key constraint is "in-place" — you cannot allocate a new array. You must modify the original array so that the first k elements contain only values that are not equal to val, and then return k. The elements beyond index k do not matter.
This is important: the problem explicitly states that the order of remaining elements can be changed. You do not need to preserve relative order (though the standard two-pointer approach does preserve it). This flexibility opens up a second approach we will cover shortly.
Pattern Connection
Remove Element (#27) is the simplest partition problem — it uses the exact same two-pointer technique as Remove Duplicates (#26) and Move Zeroes (#283), just with a different skip condition.
Two Pointer Approach — The Standard Remove Element LeetCode Solution
The two pointer remove technique works by maintaining two indices. The slow pointer (often called i or write) marks the position where the next non-val element should go. The fast pointer (often called j or read) scans through every element in the array.
For each element at the fast pointer: if it does not equal val, copy it to the slow pointer position and increment slow. If it does equal val, skip it — just advance fast. When fast reaches the end, slow equals the count of non-val elements.
This runs in O(n) time with O(1) extra space. Every element is examined exactly once by fast, and at most copied once by slow. The approach naturally preserves the relative order of non-val elements, which is a bonus even though the problem does not require it.
- Initialize slow = 0, fast = 0
- If nums[fast] != val, set nums[slow] = nums[fast] and increment slow
- If nums[fast] == val, skip — just increment fast
- Return slow as the new length
Swap with End: When Val Is Rare
There is a second approach that can be slightly more efficient when the value to remove appears infrequently. Instead of scanning left to right and copying forward, you swap each occurrence of val with the last element and shrink the array from the end.
Start with i = 0 and n = nums.length. When nums[i] equals val, swap it with nums[n - 1] and decrement n (but do not advance i, because the swapped element needs to be checked). When nums[i] does not equal val, advance i. Stop when i reaches n.
This approach also runs in O(n) time and O(1) space, but it minimizes the total number of copy operations. If val appears only once in a million-element array, the standard approach copies 999,999 elements forward. The swap-with-end approach performs just one swap.
- Initialize i = 0, n = nums.length
- If nums[i] == val, set nums[i] = nums[n-1] and decrement n (do NOT advance i)
- If nums[i] != val, advance i
- Return n when i reaches n
Order Not Required
Order doesn't need to be maintained — the problem explicitly says 'the order of elements can be changed.' This opens up the swap-with-end approach for a slight optimization.
Visual Walkthrough of Remove Element In Place
Let us trace the standard two-pointer approach on two examples to make the mechanics concrete.
Example 1: nums = [3, 2, 2, 3], val = 3. Start with slow = 0. Fast scans: index 0 is 3 (skip), index 1 is 2 (copy to slow=0, slow becomes 1), index 2 is 2 (copy to slow=1, slow becomes 2), index 3 is 3 (skip). Final array: [2, 2, _, _]. Return 2.
Example 2: nums = [0, 1, 2, 2, 3, 0, 4, 2], val = 2. Slow = 0. Fast scans: 0 (copy, slow=1), 1 (copy, slow=2), 2 (skip), 2 (skip), 3 (copy, slow=3), 0 (copy, slow=4), 4 (copy, slow=5), 2 (skip). Final array: [0, 1, 3, 0, 4, ...]. Return 5.
Notice how slow only advances when a non-val element is placed. The elements beyond index slow are irrelevant — the caller only reads the first slow elements.
Edge Cases to Watch For
Edge cases for remove element in place are straightforward but worth verifying before you submit.
Empty array: if nums has length 0, the loop never executes and you return 0. No special handling needed — the two-pointer approach handles this naturally.
All elements equal val: every element is skipped, slow never advances, and you return 0. The array effectively becomes empty.
No elements equal val: every element is copied in place, slow reaches nums.length, and you return the original length. Nothing changes.
Single element: either it matches val (return 0) or it does not (return 1). Both approaches handle this correctly without any edge-case branching.
- Empty array → return 0 (loop does not execute)
- All same as val → return 0 (slow never moves)
- None match val → return original length
- Single element → return 0 or 1 depending on match
Key Insight
The two-pointer approach copies non-val elements to the front — slow always points to the next write position. When fast finds a non-val element, copy it to slow and advance both.
What Remove Element Teaches You
The remove element leetcode problem may look trivial, but it teaches the most fundamental in-place array technique in all of interview prep: the read-write pointer partition. This exact pattern reappears in dozens of problems across LeetCode.
Remove Duplicates from Sorted Array (#26) uses the same approach but skips when nums[fast] equals nums[slow - 1]. Move Zeroes (#283) uses it but skips zeroes and then fills the tail. Sort Colors (#75) extends it to a three-way partition. Once you internalize the slow/fast pointer framework from this problem, all of those become variations on a theme.
Practice this pattern until the setup — slow = 0, scan with fast, copy or skip based on condition — is automatic. YeetCode flashcards can help you drill the pattern so you recognize it instantly in interviews, rather than re-deriving the logic under pressure.