Remove Element — The Fast and Slow Pointer Pattern at Amazon and Microsoft

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Problem Statement

Given an integer array nums and an integer val, remove all occurrences of val from nums in place. The relative order of the remaining elements may be changed. Return the number of elements remaining.

Constraints:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100
Input:  nums = [3,2,2,3], val = 3
Output: 2, nums = [2,2,_,_]
Input:  nums = [0,1,2,2,3,0,4,2], val = 2
Output: 5, nums = [0,1,3,0,4,_,_,_]

Why This Problem Matters

LeetCode 27 Remove Element is the introductory problem for the fast and slow two pointer pattern. Amazon, Microsoft, and Google use it as a 10 minute warm-up to verify that candidates can write an in-place algorithm with two indices that advance independently.

The problem is rated Easy, but it is a common rejection trigger. Candidates who reach for a new array, who use del inside a loop and corrupt the iteration, or who fail to return the new length all fail this question. Interviewers pay close attention to whether the read pointer always advances while the write pointer only advances on a keep decision.

The fast and slow pattern reappears in LC 26 Remove Duplicates from Sorted Array, LC 80 Remove Duplicates II, LC 283 Move Zeroes, LC 905 Sort Array By Parity, and a long list of in-place rearrangement problems.

The Core Insight

We need two indices: a read index i that scans every element, and a write index k that points to where the next kept element should go. Whenever nums[i] is not equal to val, copy it to nums[k] and advance both pointers. Whenever nums[i] equals val, advance only the read pointer, leaving the write pointer in place.

When the scan completes, k equals the count of kept elements and the first k slots of nums contain those elements in their original relative order. The slots beyond k are irrelevant.

This is strictly stronger than mutating with del or pop inside a loop, which is O(n^2) and prone to skipping elements when indices shift.

Visual Dry Run

For nums = [0, 1, 2, 2, 3, 0, 4, 2], val = 2:

StepRead iWrite knums[i]ActionArray
1000keep[0,1,2,2,3,0,4,2]
2111keep[0,1,2,2,3,0,4,2]
3222skip[0,1,2,2,3,0,4,2]
4322skip[0,1,2,2,3,0,4,2]
5423keep[0,1,3,2,3,0,4,2]
6530keep[0,1,3,0,3,0,4,2]
7644keep[0,1,3,0,4,0,4,2]
8752skip[0,1,3,0,4,0,4,2]

Return 5.

Solution (Optimal)

class Solution:
    def removeElement(self, nums: list[int], val: int) -> int:
        k = 0
        for i in range(len(nums)):
            if nums[i] != val:
                nums[k] = nums[i]
                k += 1
        return k
var removeElement = function(nums, val) {
    let k = 0;
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] !== val) {
            nums[k] = nums[i];
            k++;
        }
    }
    return k;
};

Time: O(n) — single pass with the read pointer Space: O(1) — only two indices

Common Mistakes

  • Calling nums.remove(val) in a loop, which is O(n^2) and shifts indices unpredictably
  • Forgetting to return k, which is what the grader actually checks
  • Using del nums[i] inside a for i in range(len(nums)) loop, skipping elements after deletion
  • Allocating a new array, which violates the in-place constraint even though it produces a correct length
  • Confusing the keep condition with the skip condition and removing the wrong elements

Interview Tips

  • Say "fast and slow pointers" out loud so the interviewer hears the pattern recognition
  • Walk through one example highlighting which pointer advances on each step
  • Note that the order of remaining elements is preserved by this template, even though the problem allows any order
  • Mention that the slots beyond k may contain stale data and that the grader ignores them

Follow-up Questions

  • What if you must preserve the relative order? (Hint: this template already does)
  • What if you must move zeros to the end instead of removing them? (Hint: LC 283, swap instead of overwrite)
  • How would you remove duplicates from a sorted array? (Hint: LC 26, compare against nums[k - 1])
  • What if at most two duplicates are allowed? (Hint: LC 80, compare against nums[k - 2])
  • How would you handle this on a singly linked list? (Hint: LC 203, fast and slow with a dummy head)

Key Takeaways

  • LeetCode 27 Remove Element introduces the fast and slow pointer template
  • Read pointer always advances, write pointer advances only on a keep decision
  • Returns the new length k while leaving stale data beyond it untouched
  • O(n) time and O(1) space, no allocations required
  • Pattern reappears in LC 26, LC 80, LC 283, LC 905, and many in-place rearrangement problems
  • Avoid remove and del inside loops, which are O(n^2) and skip elements
  • Interviewers verify that you understand why the two indices advance independently

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading