Remove Element
Difficulty: Easy Source: NeetCode
Problem
Given an integer array
numsand an integerval, remove all occurrences ofvalinnumsin-place. The order of the elements may be changed. Returnk— the number of elements innumsthat are not equal toval.The first
kelements ofnumsmust contain the elements which are not equal toval. The remaining elements and the size of the array do not matter.Example 1: Input:
nums = [3, 2, 2, 3],val = 3Output:2,nums = [2, 2, _, _]Example 2: Input:
nums = [0, 1, 2, 2, 3, 0, 4, 2],val = 2Output:5,nums = [0, 1, 3, 0, 4, _, _, _]Constraints:
0 <= nums.length <= 1000 <= nums[i] <= 500 <= val <= 100
Prerequisites
Before attempting this problem, you should be comfortable with:
- Arrays — understanding in-place modification and index-based access
- Two Pointers — using separate read and write indices to process an array in a single pass
1. Brute Force
Intuition
When an element equal to val is found, shift every element after it one position to the left to fill the gap, then shrink the logical length by one. Repeat until the full array has been scanned. This mimics how a naive deletion from a static array works.
Algorithm
- Set
k = len(nums)as the logical length. - Set
i = 0. Whilei < k:- If
nums[i] == val, shift all elements fromi+1tok-1one position left, then decrementk. - Otherwise, increment
i.
- If
- Return
k.
Solution
def removeElement(nums, val):
k = len(nums)
i = 0
while i < k:
if nums[i] == val:
for j in range(i + 1, k):
nums[j - 1] = nums[j]
k -= 1
else:
i += 1
return k
nums = [3, 2, 2, 3]
k = removeElement(nums, 3)
print(k, nums[:k]) # 2 [2, 2]
nums = [0, 1, 2, 2, 3, 0, 4, 2]
k = removeElement(nums, 2)
print(k, nums[:k]) # 5 [0, 1, 3, 0, 4]
Complexity
- Time:
O(n²) - Space:
O(1)
2. Two Pointers
Intuition
Use two pointers: a write pointer k that tracks where the next kept element should go, and a read pointer that iterates through every element. Whenever the current element is not val, copy it to position k and advance k. Elements equal to val are simply skipped. One pass through the array is enough.
Algorithm
- Initialize
k = 0as the write pointer. - For each element
numinnums:- If
num != val: writenumtonums[k], then incrementk.
- If
- Return
k.
flowchart LR
S(["nums=[3,2,2,3] val=3 k=0"])
S --> i0["i=0 → 3 = val → skip"]
i0 --> i1["i=1 → 2 ≠ val → nums[0]=2 k=1"]
i1 --> i2["i=2 → 2 ≠ val → nums[1]=2 k=2"]
i2 --> i3["i=3 → 3 = val → skip"]
i3 --> R(["return k=2 nums[:2]=[2,2]"])
Solution
def removeElement(nums, val):
k = 0
for num in nums:
if num != val:
nums[k] = num
k += 1
return k
nums = [3, 2, 2, 3]
k = removeElement(nums, 3)
print(k, nums[:k]) # 2 [2, 2]
nums = [0, 1, 2, 2, 3, 0, 4, 2]
k = removeElement(nums, 2)
print(k, nums[:k]) # 5 [0, 1, 3, 0, 4]
Complexity
- Time:
O(n) - Space:
O(1)
3. Two Pointers — II
Intuition
When there are few elements to remove, the previous approach does unnecessary copying — it rewrites every non-val element even if it is already in the right place. Instead, swap unwanted elements with the element at the end of the valid range and shrink that range by one. This minimises write operations when removals are rare.
Algorithm
- Initialize
i = 0as the current position andn = len(nums)as the effective length. - While
i < n:- If
nums[i] == val: overwrite it withnums[n - 1]and decrementn. Do not incrementi— the swapped-in element still needs to be checked. - Otherwise: increment
i.
- If
- Return
n.
flowchart LR
subgraph T0["Initial i=0 n=4"]
A0["3"] --- A1["2"] --- A2["2"] --- A3["3"]
end
subgraph T1["i=0 3=val → nums[0]=nums[3] n=3"]
B0["3"] --- B1["2"] --- B2["2"] --- B3["·"]
end
subgraph T2["i=0 3=val → nums[0]=nums[2] n=2"]
C0["2"] --- C1["2"] --- C2["·"] --- C3["·"]
end
subgraph T3["i=0,1 advance → i=2 ≥ n=2 → stop"]
D0["2"] --- D1["2"]
end
T0 --> T1 --> T2 --> T3
Solution
def removeElement(nums, val):
i = 0
n = len(nums)
while i < n:
if nums[i] == val:
n -= 1
nums[i] = nums[n]
else:
i += 1
return n
nums = [3, 2, 2, 3]
k = removeElement(nums, 3)
print(k, nums[:k]) # 2 [2, 2]
nums = [0, 1, 2, 2, 3, 0, 4, 2]
k = removeElement(nums, 2)
print(k, nums[:k]) # 5 [0, 1, 3, 0, 4]
Complexity
- Time:
O(n) - Space:
O(1)
When to prefer this over Two Pointers — I? When
valis rare, this approach writes far fewer elements. If the array has 10 000 elements and only 2 matchval, Two Pointers — I still copies 9 998 elements; this approach writes only 2.
Common Pitfalls
Indexing into nums after returning k.
The problem only guarantees that the first k elements are correct. Elements at index k and beyond are considered garbage — do not read or compare them.
Modifying nums length directly.
Python lists support del and remove(), but the problem requires in-place modification that works within the array’s original memory. Avoid creating a new list; overwrite in place and track k yourself.
Off-by-one when using k as a slice bound.
nums[:k] is correct because k is the count of valid elements, which equals the exclusive upper bound of the slice.