LeetCode #217 Easy

Contains Duplicate

Contains Duplicate is LeetCode 217 (Easy). Given an integer array nums, return true if any value appears at least twice, and false if every element is distinct.

  • Values go from -10⁹ to 10⁹, so they cannot be used as indexes into a counting array.
  • With up to 10⁵ elements, comparing every pair (about 5 · 10⁹ checks) is too slow; the target is one pass.
Constraints
  • 1 <= nums.length <= 10⁵
  • -10⁹ <= nums[i] <= 10⁹
arrayhash-tablesorting
Open on LeetCode ↗
02

Intuition

The brute force compares every pair, re-checking the same earlier values again and again. But the only fact it needs about the past is which values have appeared, not where or how often.

A hash set stores exactly that and answers "have I seen this?" in O(1) on average. So the solution walks the array once and asks that one question for each value. The first "yes" is the answer.

How to spot this pattern

Any "has this value appeared before?" question is a hash-set question: as soon as an inner loop only re-scans elements already walked past, replace it with a set lookup. The same move powers Two Sum (a map from value to index) and Longest Consecutive Sequence. When the repeat must also be close by, as in Contains Duplicate II, the set becomes a sliding window.

03

Approach

Try it first

Before reading on: the brute force compares every pair. What does it keep re-checking, and what is the least you would need to remember so each element is looked at only once? Trace [1, 2, 3, 1] with that memory.

1

Start with an empty set

seen = set() will hold every value already walked past. A set answers membership in O(1) on average, so one lookup replaces the brute force's inner loop.

2

Check each value, then add it

For each num, first ask whether it is in seen. If it is, an earlier index holds the same value, so return true straight away; nothing later can change the answer. Otherwise add num so that any later copy will find it.

3

Return false after the loop

Reaching the end means every lookup missed, so all n values are distinct. Each element cost one lookup and at most one insert, giving O(n) time and O(n) space for the set.

04

Contains Duplicate solution in Python | C++ | Java

▶1class Solution:
▶2 def containsDuplicate(self, nums: List[int]) -> bool:
▶3 seen = set()
▶4 for num in nums:
▶5 if num in seen:
▶6 return True
▶7 seen.add(num)
▶8 return False
nums01122331seenemptyseen starts empty
seenemptyhash set
Start. The set will hold every value already walked past. A set lookup costs O(1) on average, so each element needs one question instead of a scan of everything before it.
nums01122331seenempty1 not in seen
num1nums[0]
in seen?no
seenempty
Look up 1 before adding it. It is not in the set, so no earlier index holds the same value.
nums01122331seen1add 1 to seen
seen{1}1 remembered
Add 1 to the set now, after the check. If a later element equals 1, its lookup will find it here, so index 0 never has to be visited again.
nums01122331seen12 not in seen
num2nums[1]
in seen?no
seen{1}
Look up 2 before adding it. It is not in the set, so no earlier index holds the same value. One lookup checked the earlier value at once; that is the inner loop the set replaces.
nums01122331seen12add 2 to seen
seen{1, 2}2 remembered
Add 2 to the set now, after the check. If a later element equals 2, its lookup will find it here, so index 1 never has to be visited again.
nums01122331seen123 not in seen
num3nums[2]
in seen?no
seen{1, 2}
Look up 3 before adding it. It is not in the set, so no earlier index holds the same value. One lookup checked all 2 earlier values at once; that is the inner loop the set replaces.
nums01122331seen123add 3 to seen
seen{1, 2, 3}3 remembered
Add 3 to the set now, after the check. If a later element equals 3, its lookup will find it here, so index 2 never has to be visited again.
nums01122331seen1231 is in seen → duplicate
num1nums[3]
in seen?yes
seen{1, 2, 3}
1 is already in the set. It was added at index 0, so the same value sits at two different indices. That is exactly what the problem asks about, so there is nothing left to learn from the rest of the array.
nums01122331seen123return true
answertrue
Answer: true. The loop stops at index 3. The early return is why a repeat near the front is found in a few steps, however long the array is.
05

Sorting version

Sorting puts equal values next to each other, so a single pass comparing each element with the one before it finds any duplicate.

▶1class Solution:
▶2 def containsDuplicate(self, nums: List[int]) -> bool:
▶3 nums.sort()
▶4 for i in range(1, len(nums)):
▶5 if nums[i] == nums[i - 1]:
▶6 return True
▶7 return False
06

Common pitfalls

Adding before checking

✗ Wrong
for num in nums:
    seen.add(num)
    if num in seen:
        return True
✓ Right
for num in nums:
    if num in seen:
        return True
    seen.add(num)

The value just inserted is always found, so this returns true on the first element of every input, including [1, 2, 3, 4].

Using a list instead of a set

✗ Wrong
seen = []
if num in seen: ...
✓ Right
seen = set()
if num in seen: ...

in on a list scans it element by element, so the solution quietly becomes O(n²) and times out on 10⁵ distinct values. The syntax is the same, which is why it is easy to miss.

07

Complexity

Time
O(n)
Space
O(n)
One pass; the set holds at most n values. Sorting instead costs O(n log n) time but needs no set.
08

Contains Duplicate I, II and III

The three problems share a name but ask different questions, so the data structure changes.

ProblemAsksTool
217 Contains Duplicate (this page)any value twice, anywherehash set of all values
219 Contains Duplicate IIequal values at most k indices apartset of the last k values (sliding window)
220 Contains Duplicate IIIvalues within t of each other, at most k apartbuckets of width t + 1, or an ordered set
09

Contains Duplicate FAQ

Is len(set(nums)) != len(nums) a good Python answer?

Yes, it is correct and accepted on LeetCode. It always builds the full set before answering, so it cannot stop early on an input like [1, 1, ...], and an interviewer will usually ask you to explain the loop it hides, which is the solution on this page.

Why use a hash set and not a hash map?

Only the presence of a value matters, not a count or an index, so the set stores less. A map from value to count also works but does extra bookkeeping the answer never uses.