easyLeetCodeNot Started

Remove Element

A curated StudyFlow practice problem with comprehensive editorial and multi-language solutions.

Solve on LeetCode
Lesson

Problem Statement

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.

Consider the number of elements in nums which are not equal to val be k, to get accepted, you need to do the following things: - Change the array nums such that the first k elements of nums contain the elements which are not equal to val. - The remaining elements of nums are not important as well as the size of nums. - Return k.

Example 1 · Standard Array with 2 Target Elements:

Input: nums = [3, 2, 2, 3], val = 3
Output: 2, nums = [2, 2, _, _]
Explanation: Your function should return k = 2, with the first two elements of nums being 2. It does not matter what you leave beyond the returned k.

Example 2 · 8-element Array with Target Value 2:

Input: nums = [0, 1, 2, 2, 3, 0, 4, 2], val = 2
Output: 5, nums = [0, 1, 3, 0, 4, _, _, _]
Explanation: Your function should return k = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4 in any order.

Example 3 · Target Value Not Present in Array:

Input: nums = [1, 2, 3, 4], val = 5
Output: 4, nums = [1, 2, 3, 4]
Explanation: Target value 5 does not exist in nums. Returns k = 4 and array remains unchanged.

Constraints:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

Prerequisites

Before attempting this problem, you should be comfortable with:

  • Two Pointers technique
  • In-place array overwriting
  • Understanding mutable array return contracts

What You'll Learn

Key principles and algorithmic techniques you will master from this problem:

  • Master the forward write-pointer compaction technique.
  • Implement the 'Swap with Last' technique to minimize total write operations.
  • Handle boundary edge cases (empty array, all elements equal to val).
  • Write concise solutions across C++, Java, Python, and JavaScript.

Pattern Recognition Trigger

How to instantly recognize this algorithmic pattern when encountering unseen interview questions:

Signals to Look For:

  • Asked to filter out all occurrences of a specific target value in-place.
  • Order of remaining elements does NOT need to be preserved (allows swapping with tail).
  • Requires O(1) auxiliary space.

Algorithmic Decision Tree:

  • If order must be kept: Use forward Slow/Fast Two Pointers (nums[write++] = nums[read]).
  • If order does NOT matter and target elements are rare: Swap target with the last element (nums[i] = nums[n - 1]; n--).

Connected Patterns:

Two PointersSliding WindowPrefix Sum

1. Brute Force — Auxiliary Array Copy

Intuition

Copy all elements not equal to val into a temporary array, then copy them back to nums.

Algorithm

  1. Initialize an empty list temp.
  2. For each number x in nums:
  3. If x != val, append x to temp.
  4. Copy temp elements back to nums[0 ... temp.length - 1].
  5. Return temp.length.

Auxiliary Array Copy

2 of 2 questions left today
Step 1 / 6
Trace timeline17% explored
InputINPUT nums = [3, 2, 2, 3]
Current operationSTEP 1 OF 6
Phase 1 — Scan Index 0: nums[0] is 3
Visual state
Values and pointers at this exact step
array
S
3
2
2
3
0
↑ i = 0
1
2
3
Variables at this step
Index
0
Value
3
val
3
temp
[]
Check / comparison
nums[0] (3) == val (3) -> discard.
Decision / next transition
Skip element. temp list: [].
Why this step matters

Phase 1 — Scan Index 0: nums[0] is 3. Compare with target val = 3. 3 == 3, so skip this element.

Step 1 / 6
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3using namespace std;
4
5// Brute Force: Auxiliary array copy (O(N) space)
6int removeElement(vector<int>& nums, int val) {
7 vector<int> temp;
8 for (int num : nums) {
9 if (num != val) {
10 temp.push_back(num);
11 }
12 }
13
14 for (size_t i = 0; i < temp.size(); i++) {
15 nums[i] = temp[i];
16 }
17 return temp.size();
18}
19
20int main() {
21 vector<int> nums = {3, 2, 2, 3};
22 int val = 3;
23 int k = removeElement(nums, val);
24
25 cout << "k = " << k << ", nums = [";
26 for (int i = 0; i < k; i++) {
27 cout << nums[i] << (i + 1 < k ? ", " : "");
28 }
29 cout << "]" << endl;
30 return 0;
31}

Time & Space Complexity

  • Time complexity: O(N^2) — Time complexity for Approach 1: Brute Force — Auxiliary Array Copy.
  • Space complexity: O(1) — Space complexity for Approach 1: Brute Force — Auxiliary Array Copy.

Why Brute Force Doesn't Scale:

For N = 105, quadratic O(N2) approaches require ~1010 operations, exceeding the standard 1-second CPU budget.

The optimal approach processes N elements in a single or logarithmic pass, completing in under 10ms with minimal memory footprint.


2. Better — Forward Slow/Fast Two Pointers

Intuition

Maintain write pointer at 0. Scan read pointer through array; whenever nums[read] != val, write nums[write] = nums[read] and increment write.

Algorithm

  1. Initialize write = 0.
  2. Loop read from 0 to nums.length - 1:
  3. If nums[read] != val:
  4. nums[write] = nums[read].
  5. write++.
  6. Return write.

Forward Two Pointers (Slow / Fast)

2 of 2 questions left today
Step 1 / 6
Trace timeline17% explored
InputINPUT nums = [3, 2, 2, 3]
Current operationSTEP 1 OF 6
Phase 1 — Setup Pointers: slow = 0 marks the insert position for valid elements
Visual state
Values and pointers at this exact step
array
S
3
2
2
3
0
↑ slow=0↑ fast=0
1
2
3
Variables at this step
slow
0
fast
0
nums
[3, 2, 2, 3]
Check / comparison
fast = 0: nums[0] is 3 == val (3).
Decision / next transition
Discard 3. Advance fast to 1. slow remains 0.
Why this step matters

Phase 1 — Setup Pointers: slow = 0 marks the insert position for valid elements. fast = 0 explores the array.

Step 1 / 6
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3using namespace std;
4
5// Better: Forward Two Pointers (O(N) time, O(1) space)
6int removeElement(vector<int>& nums, int val) {
7 int write = 0;
8 for (size_t read = 0; read < nums.size(); read++) {
9 if (nums[read] != val) {
10 nums[write] = nums[read];
11 write++;
12 }
13 }
14 return write;
15}
16
17int main() {
18 vector<int> nums = {0, 1, 2, 2, 3, 0, 4, 2};
19 int val = 2;
20 int k = removeElement(nums, val);
21
22 cout << "k = " << k << ", nums = [";
23 for (int i = 0; i < k; i++) {
24 cout << nums[i] << (i + 1 < k ? ", " : "");
25 }
26 cout << "]" << endl;
27 return 0;
28}

Time & Space Complexity

  • Time complexity: O(N log N) — Time complexity for Approach 2: Better — Forward Slow/Fast Two Pointers.
  • Space complexity: O(N) — Space complexity for Approach 2: Better — Forward Slow/Fast Two Pointers.

3. Optimal — Swap with Last Element (Minimal Writes)

Intuition

When elements to remove are rare, whenever nums[i] == val, swap nums[i] with the last element nums[n - 1] and decrement n without advancing i.

Algorithm

  1. Initialize i = 0 and n = nums.length.
  2. While i < n:
  3. If nums[i] == val:
  4. nums[i] = nums[n - 1].
  5. n--.
  6. Else:
  7. i++.
  8. Return n.

Swap with Last Element (Minimal In-Place Writes)

2 of 2 questions left today
Step 1 / 6
Trace timeline17% explored
InputINPUT nums = [3, 2, 2, 3]
Current operationSTEP 1 OF 6
Phase 1 — Setup Bidirectional Pointers: i = 0 scans forward
Visual state
Values and pointers at this exact step
array
S
3
2
2
3
0
↑ i=0
1
2
3
↑ n=4
Variables at this step
i
0
n
4
Swapping with
nums[3]
Check / comparison
i = 0, nums[0] is 3 == val (3).
Decision / next transition
nums[0] must be removed. Swap with nums[n-1] (nums[3]=3) and decrement n to 3.
Why this step matters

Phase 1 — Setup Bidirectional Pointers: i = 0 scans forward. n = 4 points just beyond the active boundary. When nums[i] == val, swap with nums[n - 1] and shrink n.

Step 1 / 6
C++ SOLUTIONCLEAN & OPTIMIZED
1#include <iostream>
2#include <vector>
3using namespace std;
4
5// Optimal: Swap with Last Element (Minimal Writes)
6int removeElement(vector<int>& nums, int val) {
7 int i = 0;
8 int n = nums.size();
9
10 while (i < n) {
11 if (nums[i] == val) {
12 nums[i] = nums[n - 1];
13 n--;
14 } else {
15 i++;
16 }
17 }
18 return n;
19}
20
21int main() {
22 vector<int> nums = {3, 2, 2, 3};
23 int val = 3;
24 int k = removeElement(nums, val);
25
26 cout << "k = " << k << ", nums = [";
27 for (int i = 0; i < k; i++) {
28 cout << nums[i] << (i + 1 < k ? ", " : "");
29 }
30 cout << "]" << endl;
31 return 0;
32}

Time & Space Complexity

  • Time complexity: O(N) — Time complexity for Approach 3: Optimal — Swap with Last Element (Minimal Writes).
  • Space complexity: O(1) — Space complexity for Approach 3: Optimal — Swap with Last Element (Minimal Writes).

Approach Comparison Matrix

Side-by-side comparison of time, space, and algorithmic trade-offs across each approach:

ApproachTimeSpaceCore IdeaTrade-off / Bottleneck
1.Auxiliary ArrayO(N)O(N)Very easy logic.Baseline only.
2.Forward Two PointersO(N)O(1)Maintains original relative order of remaining elements.Standard optimal solution.
3.Swap with Last ElementOptimalO(N)O(1)Minimizes total memory write operations when target elements are rare.Top-tier optimization answer.

Common Pitfalls & Crucial Edge Cases

Off-by-One Errors

Incorrect boundary indexing when adjusting pointers or array slices.

Integer Overflow

Using 32-bit signed integer types when accumulative operations exceed 231 - 1 in C++/Java.

Unnecessary Memory Allocation

Allocating large auxiliary arrays or objects inside inner loops causing GC overhead.

Failing to Reset Loop State

Not re-initializing state variables or counters between iterations or subproblems.

Crucial Edge Cases to Validate:

  • All Elements Equal to val — Input: nums = [2, 2, 2, 2], val = 2, Expected: 0, nums = [] — All elements removed; returns k = 0.
  • No Elements Equal to val — Input: nums = [1, 2, 3, 4], val = 7, Expected: 4, nums = [1, 2, 3, 4] — No elements removed; returns k = 4.
  • Empty Array — Input: nums = [], val = 0, Expected: 0, nums = [] — Empty array returns 0 immediately.

Interview Tips & Best Practices

How to communicate your thought process and address follow-ups in a live technical interview:

  1. Always state the brute force baseline before presenting the optimal solution to demonstrate structured problem solving.
  2. Explicitly verify boundary conditions (empty arrays, single elements, duplicates, extremes) out loud with the interviewer.
  3. Analyze both time and auxiliary space complexities clearly, explaining trade-offs between speed and memory allocation.

Quick Comprehension Check

Test your intuitive understanding of the core concept in 30 seconds:

1.What is the optimal time and auxiliary space complexity for Remove Element?

2.Why is the brute force approach suboptimal for large inputs in Remove Element?

3.Which data structure or technique enables the optimal solution for Remove Element?