2Brute2Best
🔥0

Find All Duplicates in an Array

Medium·LeetCode #442Basic Anchor
LeetCode
30-Second Mental ModelCyclic Sort — Duplicate number (squatters after placement)
Complexity:O(N²)→O(N)
Key Insight

Use the array itself as the count array. Value v has the home nums[v − 1]. Swap every value home. A value that appears once ends up at its home. For a value that appears twice, one copy gets home and the other cannot — its home is taken by its twin. That stuck copy sits at some wrong index. So after placement, every i with nums[i] != i + 1 holds a duplicate.

Core Validity Invariant

Keep swapping nums[i] home while nums[i] != nums[nums[i] − 1]. After that, every index with nums[i] != i + 1 holds a duplicate value.

01

Problem

You are given an array nums of length n. Every value is between 1 and n, and every value appears once or twice.

Return every value that appears twice. The order of the answer does not matter.

Your algorithm must run in O(N) time and use only O(1) extra space (the output list does not count).

Input

An integer array nums of length n, with 1 ≤ nums[i] ≤ n.

Output

A list of all values that appear exactly twice, in any order.

Example 1
Input: nums = [4, 3, 2, 7, 8, 2, 3, 1]
Output: [2, 3]

2 and 3 each appear twice. Every other value appears once.

Example 2
Input: nums = [1, 1, 2]
Output: [1]

1 appears twice.

Example 3
Input: nums = [1]
Output: []

Nothing repeats, so the answer is empty.

Constraints
  • • n == nums.length
  • • 1 ≤ n ≤ 10^5
  • • 1 ≤ nums[i] ≤ n
  • • Each value appears once or twice.
  • • O(N) time and O(1) extra space (not counting the output).
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 1.

    The values are 1..n and the array has n slots. Is there a natural slot for each value?

  2. 2.

    If I had unlimited memory, how would I notice that I am seeing a value for the second time?

  3. 3.

    If two copies of the same value both want the same slot, what happens to the second one?

  4. 4.

    When I move a value to its slot, where does the old resident go?

  5. 5.

    When should I stop swapping at a position so the loop cannot run forever?

03

Brute force approach

04

Better approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceFor each i, look for an equal value at some j > iO(N²)O(1)
BetterCount each value in an array of size n + 1; report at count 2O(N)O(N)
OptimalSwap each value v home to index v − 1; values not at home are duplicatesO(N)O(1)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “values between 1 and n”Each value has a home index v − 1 inside the array.
  • “appears once or twice”At most one extra copy per value — it will be the one left out of place.
  • “O(1) extra space”No count array or hash set — the input must store "seen" itself.
  • “return all duplicates”Read the answer off every misplaced slot, not just the first one.
values in 1..n+find what repeats+O(1) extra space→Cyclic Sort — Duplicate number (squatters after placement)

This is the anchor of the duplicate sub-pattern. In the missing sub-pattern you read the index of a bad slot (i + 1 is missing). Here you read the value in the bad slot (nums[i] is a duplicate). It is the same placement loop; only what you collect afterwards changes. The stop condition must compare with the home's value, because the twin may already be sitting there.

10

Don't make this mistake

Stopping on the wrong condition (infinite loop)
✗ while (nums[i] != i + 1) swap(nums[i], nums[nums[i] - 1]);
✓ while (nums[i] != nums[nums[i] - 1]) swap(nums[i], nums[nums[i] - 1]);

This is the pattern-confusion trap from plain cyclic sort, where every value is distinct. Here a value can repeat. On [1, 1], at i = 1 the value 1 is not at index 1, so the wrong loop swaps it with index 0 — which also holds 1. Nothing changes and the loop never ends. Check the home's value instead.

Reporting the index instead of the value
✗ if (nums[i] != i + 1) result.push_back(i + 1);
✓ if (nums[i] != i + 1) result.push_back(nums[i]);

i + 1 is the value missing from the array (that is the Find All Numbers Disappeared question). The value sitting in the bad slot is the duplicate.

Using if instead of while
✗ if (nums[i] != nums[nums[i] - 1]) swap(nums[i], nums[nums[i] - 1]);
✓ while (nums[i] != nums[nums[i] - 1]) swap(nums[i], nums[nums[i] - 1]);

After one swap, the value that lands at i may also need to move. On [4, 3, 2, 7, 8, 2, 3, 1] a single swap per index ends with [7, 2, 3, 4, 1, 2, 3, 8] and reports [7, 1, 2, 3] instead of [2, 3].

Sorting or a hash set
✗ sort(nums.begin(), nums.end()); // O(N log N) // or unordered_map<int, int> cnt; // O(N) space

Both find the duplicates, and the judge may accept them, but they break the stated limits. The values being 1..n is the signal that the array can be its own count array.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like Cyclic Sort translate into production architectures and low-level memory mechanics.