Problem
You're given an array of n integers where every value falls in the range [1, n]. Because of duplicates, some numbers in that range never appear. Return a list of all the missing ones.
- Input:
nums = [4, 3, 2, 7, 8, 2, 3, 1] - Output:
[5, 6] - Explanation: The array has length 8, so the full range is 1โ8; the numbers 5 and 6 never appear.
Counter-example: nums = [1, 1] โ output [2], because 2 is never seen and 1 appears twice.
Intuition
Every value in the array is a valid 1-based index into that same array. That means you can use the values themselves to leave a mark โ without any extra storage โ by negating the element at the corresponding position. After one pass, any index whose value is still positive points to a number that was never visited.
Approach 1 โ Hash Set
Store every number seen in a set, then sweep 1 through n to collect anything absent.
- Add all elements of
numsto a hash set. - Iterate
ifrom1ton(inclusive). - If
iis not in the set, append it to the result. - Return the result list.
1def findDisappearedNumbers(nums: list[int]) -> list[int]:
2 seen = set(nums)
3 return [num for num in range(1, len(nums) + 1) if num not in seen]Time: O(n) โ one pass to build the set, one pass to find gaps.
Space: O(n) โ the hash set holds up to n distinct values.
Approach 2 โ In-Place Index Marking
Use the array itself as a visited map by negating the element at index abs(num) - 1 for every number encountered. Indices that remain positive after the full pass correspond to missing numbers.
- For each
numinnums, computeindex = abs(num) - 1(useabsbecause a prior iteration may have already negated this slot). - If
nums[index]is positive, negate it to mark that value as seen. - After the loop, iterate through
numswith indexi. - If
nums[i] > 0, the valuei + 1was never encountered โ add it to the result. - Return the result list.
1def findDisappearedNumbers(nums: list[int]) -> list[int]:
2 for num in nums:
3 index = abs(num) - 1 # recover original value even if already negated
4 if nums[index] > 0:
5 nums[index] = -nums[index] # mark this slot as visited
6
7 # slots still positive were never marked โ their 1-based index is missing
8 return [i + 1 for i, val in enumerate(nums) if val > 0]Time: O(n) โ two linear passes over the array.
Space: O(1) โ the marking is done in-place; the output list is not counted.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Hash Set | O(n) | O(n) | When you cannot mutate the input array |
| In-Place Marking | O(n) | O(1) | When mutation is allowed and you want to avoid extra allocation |
Common Mistakes
- Reading
numdirectly as an index instead ofabs(num)โ a duplicate value may have already been negated in an earlier iteration, so you must take the absolute value before using it as an index. - Negating without checking the sign first โ if a slot is already negative and you negate it again you restore it to positive, incorrectly un-marking a visited number.
- Off-by-one on the index โ values are 1-based but arrays are 0-based, so the index is
abs(num) - 1, notabs(num). - Returning
iinstead ofi + 1โ the final pass collects 0-based indices, but the answer requires 1-based missing values. - Allocating a separate boolean array โ a
visited[n]array has the same O(n) space cost as the hash set; the whole point of the in-place approach is to avoid that extra allocation entirely.
Related Problems
find-all-duplicates-in-an-arrayโ identical negation trick, but you collect indices marked twice instead of those never markedfirst-missing-positiveโ harder variant: find the smallest missing positive with the same O(1)-space constraintmissing-numberโ find the single missing value in [0, n]; simpler but the same "values-as-indices" thinkingcontains-duplicateโ detect whether any value appears more than once, a prerequisite intuition for this problemfind-the-duplicate-numberโ uses cycle detection or index marking to find a repeated value in [1, n]