Find All Duplicates in an Array
Problem
Given an integer array nums of length n where all elements are in the range [1, n], return an array of all the elements that appear twice in this array.
- n == nums.length
- 1 ≤ n ≤ 10⁵
- 1 ≤ nums[i] ≤ n
- Each element appears once or twice
Example
nums = [4,3,2,7,8,2,3,1][2,3]A naive approach would count frequencies using extra space, but this violates the O(1) space constraint. The algorithm uses the input array itself to track seen numbers by negating the value at the index corresponding to each number. When a number's corresponding index is already negative, it indicates the number has appeared before and is a duplicate. For example, when processing the second '2', the value at index 1 (2 - 1) is already negative, so '2' is appended to the result.
Approach
Straightforward Solution
A brute-force approach uses a hash map or frequency array to count occurrences, which requires O(n) extra space and is not optimal for space-constrained scenarios.
Core Observation
Each number in nums is in the range [1, n], which means each number can be mapped to an index in the array (number - 1). This allows the array itself to be used as a hash-like structure by marking visited indices.
Path to Optimal
PreviewThe key insight is to use the sign of the element at the mapped index to indicate whether the number has been seen before. When a number is encountered, the algorithm negates the value at its corresponding index if it is positive…
Full step-by-step walkthrough on Pro →
Optimal Approach
PreviewIterate through nums, for each number compute index = abs(num) - 1. If nums[index] is positive, negate it to mark as visited…
Full step-by-step walkthrough on Pro →
Want the full reasoning chain?
Unlock the complete walkthrough, line-by-line analysis, and recall drill.
Unlock ProTime
O(n)
The algorithm makes a single pass through the array, performing O(1) operations per element.
Space
O(1)
The solution uses the input array itself for marking and only a constant amount of extra space for the result array, which is required by the problem output.
Pattern Spotlight
Cyclic Sort (In-Place Index Marking)
When elements are constrained to a range [1, n], use the array indices as markers by negating or swapping elements to track presence or duplicates without extra space.
Solution
| 1 | class Solution: |
| 2 | def findDuplicates(self, nums: list[int]) -> list[int]: |
| 3 | res = [] |
| 4 | |
| 5 | for num in nums: |
| 6 | index = abs(num) - 1 |
| 7 | |
| 8 | if nums[index] < 0: |
| 9 | res.append(abs(num)) |
| 10 | else: |
| 11 | nums[index] *= -1 |
| 12 | |
| 13 | return res |
Step-by-Step Solution
Accumulate Duplicates by Marking Visited Indices via Negation
| 3 | res = [] |
| 5 | for num in nums: |
| 6 | index = abs(num) - 1 |
| 8 | if nums[index] < 0: |
| 9 | res.append(abs(num)) |
| 10 | else: |
| 11 | nums[index] *= -1 |
| 13 | return res |
Objective
To iterate through the array and use the sign of elements at mapped indices to detect duplicates.
Key Insight
By mapping each number to an index (num - 1), the algorithm uses the sign of the element at that index as a flag. Negating the element marks the number as seen. Encountering a negative value at the mapped index means the number has appeared before, so it is a duplicate. This clever in-place marking avoids extra space while preserving O(n) time.
Interview Quick-Check
Core Logic
Use the absolute value of each number to find its mapped index, then check the sign at that index to determine if the number is a duplicate or not.
State & Boundaries
Always use abs(num) to handle previously negated values and ensure correct index mapping.
Common Pitfalls & Bugs
Failing to use abs(num) can cause incorrect index calculations due to negative values, leading to wrong results or index errors.
Complexity
This approach achieves O(n) time and O(1) auxiliary space by modifying the input array in place.
Line Analysis
This solution has 3 Critical lines interviewers watch for.
if nums[index] < 0:
Check if the value at the mapped index is negative, indicating the number has been seen before.
A negative value at this index signals that the corresponding number has already been encountered, so the current number is a duplicate.
index = abs(num) - 1
Calculate the index corresponding to the current number by taking its absolute value minus one.
Using abs(num) ensures that previously negated numbers do not affect the index calculation, maintaining correctness in the presence of in-place modifications.
else:
Otherwise, negate the value at the mapped index to mark the number as seen.
Negating the value at the mapped index flags that the number has been encountered, enabling detection of duplicates on subsequent visits.
Full line-by-line criticality + rationale for all 8 lines available on Pro.
Test Your Understanding
Why does negating the value at the mapped index correctly indicate whether a number has been seen before?
See the answer with Pro.
Don't just read it. Drill it.
Reconstruct Find All Duplicates in an Array from memory until it sticks. AlgoDrill blanks out key lines and makes you fill them back in, step by step.
Unlock the Find All Duplicates in an Array drill