Skip to main content

60. Remove Duplicates from Sorted Array II

mediumAsked at Vercel

Remove duplicates from a sorted array so each element appears at most twice, in-place. Vercel asks this as an extension of LC 26 — same two-pointer pattern with a more general invariant.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in Vercel loops.

  • Glassdoor (2026-Q1)Vercel screen; the 'at most k' generalization is the bonus.
  • Blind (2025-Q4)Listed in Vercel platform engineer screen.

Problem

Given an integer array nums sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears at most twice. The relative order of the elements should be kept the same. Return the number of elements in nums which are not equal to val.

Constraints

  • 1 <= nums.length <= 3 * 10^4
  • -10^4 <= nums[i] <= 10^4
  • nums is sorted in non-decreasing order.

Examples

Example 1

Input
nums = [1,1,1,2,2,3]
Output
5, nums = [1,1,2,2,3,_]

Example 2

Input
nums = [0,0,1,1,1,1,2,3,3]
Output
7, nums = [0,0,1,1,2,3,3,_,_]

Approaches

1. Counter map

Count occurrences; copy each element up to twice into a new array.

Time
O(n)
Space
O(n)
// O(n) extra space. Mention only as the non-in-place baseline.

Tradeoff: Violates in-place.

2. Two-pointer with k-element lookback (optimal)

Slow is the write index. For each fast, write if slow < 2 OR nums[fast] != nums[slow-2]. This generalizes to 'at most k' by comparing nums[slow-k].

Time
O(n)
Space
O(1)
function removeDuplicates(nums) {
  let slow = 0;
  for (let fast = 0; fast < nums.length; fast++) {
    if (slow < 2 || nums[fast] !== nums[slow - 2]) {
      nums[slow] = nums[fast];
      slow++;
    }
  }
  return slow;
}

Tradeoff: O(n) single pass. The `slow - 2` comparison is the trick — we know any element 2 positions back is the third-from-last kept; if the new element equals that, it's the third copy and we skip.

Vercel-specific tips

Vercel grades the slow-2 lookback. Bonus signal: generalizing to 'at most k' (replace 2 with k everywhere) and explaining the invariant: positions [0..slow) hold the answer so far; nums[slow-k] is the kth-most-recent kept value.

Common mistakes

  • Using slow - 1 — produces 'at most 1', the LC 26 version.
  • Forgetting the slow < 2 guard — accesses nums[-2] on the first two iterations.
  • Comparing fast with fast-1 instead of slow with slow-2 — measures input runs, not output runs.

Follow-up questions

An interviewer at Vercel may pivot to one of these next:

  • Generalize to at most k (any positive integer).
  • What if not sorted? Need a hash count and full pass.
  • Online streaming — bounded buffer.

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Why nums[slow - 2] and not nums[fast - 2]?

Because slow tracks the WRITE position. We care whether the new element duplicates what we've ALREADY written, not the raw input. Two positions back in the output is the third-most-recent kept value.

How does this generalize to k?

Replace 2 with k. The invariant 'at most k copies of each value' is preserved because we only write when the current value isn't a (k+1)-th repeat.

Practice these live with InterviewChamp.AI

Drill Remove Duplicates from Sorted Array II and other Vercel interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →