The problem
You get an array of integers nums. Return True if any value appears at least twice, and False if every element is distinct.
Input: [1, 2, 3, 1]
Output: True
Input: [1, 2, 3, 4]
Output: FalseIn the first array, 1 appears at index 0 and index 3.
How to think about it
Start with brute force. Compare every pair of elements. That is O(n²) time, too slow for 10⁵ elements. A better step: sort, then any duplicates sit next to each other, so one scan of neighbours finds them. That is O(n log n) time, and O(1) extra space if you’re allowed to sort in place.
The key insight: a set remembers what you’ve seen in O(1) per lookup. The question “does anything repeat?” is the most basic hash-set question there is. You could walk the list and stop at the first value already in the set. Or, more simply, build the whole set at once: a set keeps only one copy of each value, so if any value repeated, the set ends up smaller than the list.
Early exit or one-liner? The one-liner always processes the full list. The loop version (if x in seen: return True) can stop as soon as it finds a repeat, which helps on long inputs with an early duplicate. Both are O(n) in the worst case, and either is a fine interview answer if you mention the trade-off.
Which pattern is this? Hash set membership. The tell is “have I seen this value before?”
Approach
- Build a set from
nums. Duplicates collapse into one entry. - If the set’s length differs from the list’s length, something was dropped, so return
True. - Otherwise every value was unique; return
False.
Solution
def contains_duplicate(nums):
return len(set(nums)) != len(nums) # the set drops repeats, so it shrinks
# contains_duplicate([1,2,3,1]) -> TrueDry run
| Input | set(nums) |
len(set) |
len(nums) |
Result |
|---|---|---|---|---|
[1, 2, 3, 1] |
{1, 2, 3} |
3 | 4 | True |
[1, 2, 3, 4] |
{1, 2, 3, 4} |
4 | 4 | False |
[] |
set() |
0 | 0 | False |
For the example, the second 1 is dropped when the set is built, so the set has 3 elements against the list’s 4.
Complexity
- Time: O(n). Building the set inserts each element once, at O(1) average per insert.
- Space: O(n). The set can hold every element when they’re all distinct.
Edge cases and pitfalls
- Empty list or one element: no duplicates possible, returns
False. - Negative numbers and zero hash like any other integer; nothing special.
- Space-limited follow-up: if O(1) extra space is required, sort in place and check neighbours, accepting O(n log n) time.
- Large input with an early repeat: the loop-with-early-exit version is faster in practice. Mention it.
- Nearby duplicates (
|i − j| ≤ k, LeetCode 219) is a different problem. Store the last index of each value in a dictionary, or keep a sliding window set of size k.
Related problems
- Two Sum (LeetCode 1): the same “have I seen it?” lookup, with the value’s complement.
- Find the Duplicate Number (LeetCode 287): find the repeat in O(1) space without a set.
- Longest Consecutive Sequence (LeetCode 128): another problem where a set is the whole trick.
- 1.Two Sum (LeetCode 1)
- 2.Valid Anagram (LeetCode 242)
- 3.Contains Duplicate (LeetCode 217)
- 4.Ransom Note (LeetCode 383)
- 5.First Unique Character in a String (LeetCode 387)
- 6.Majority Element (LeetCode 169)
- 7.Isomorphic Strings (LeetCode 205)
- 8.Group Anagrams (LeetCode 49)
- 9.Top K Frequent Elements (LeetCode 347)
- 10.Longest Consecutive Sequence (LeetCode 128)
- 11.Subarray Sum Equals K (LeetCode 560)
- 12.Valid Sudoku (LeetCode 36)
- 13.LRU Cache (LeetCode 146)