Contains Duplicate
Contains Duplicate: Mastering Hash Sets and Early Exits
Welcome back to codinginterview.net. If you have been following our curriculum, you are getting comfortable with foundational arrays and pointers. Now, it is time to tackle a fundamental problem that appears in almost every technical assessment: Contains Duplicate. This problem is the ultimate gateway to understanding time-space tradeoffs. By the end of this guide, checking for uniqueness and utilizing high-speed lookup data structures will be second nature to you.
1. Understanding the Problem
You are given an integer array nums. Your task is to return true if any value appears at least twice in the array, and return false if every element is distinct.
The Core Constraint (The Trap):
Because arrays can contain up to 100,000 elements, checking every number against every other number using nested loops will cause a "Time Limit Exceeded" error. You must find a way to remember what you have seen in the past without sacrificing speed.
2. The Naive Approaches: Brute Force and Sorting
There are two common beginner ways to approach this:
The Brute Force: You use two nested loops. For every number, you scan the rest of the array to see if a match exists.
- Time Complexity: O(N²) — A massive performance bottleneck for large arrays.
- Space Complexity: O(1) — No extra memory is used.
The Sorting Approach: You sort the array first. Once sorted, any duplicates will be sitting right next to each other, so you only need to check adjacent elements.
- Time Complexity: O(N log N) — Better than brute force, but still not the fastest possible time.
- Space Complexity: O(1) or O(N) depending on the language's sorting algorithm.
3. The Optimal Approach: The Hash Set (O(N) Time)
To pass a senior-level technical interview, we want to achieve an O(N) time complexity. We can do this by trading a little bit of memory for a massive boost in speed using a Hash Set.
Imagine you are a bouncer at an exclusive club. Instead of memorizing every person who walks in (or making the line sort themselves alphabetically), you simply carry a clipboard with a guest list. When a person steps up, you check if their name is already on your clipboard. If it is, you caught a duplicate! If it isn't, you write their name down and let them in. Because checking a clipboard takes virtually zero time, you can process the line as fast as people walk up.
A Hash Set works exactly like this clipboard. It allows us to insert and look up numbers in constant O(1) time.
4. The Logic Step-by-Step
- Initialize the Memory: Create an empty Hash Set called
seento act as your clipboard. - Traverse the Array: Create a loop to go through each number in the
numsarray one by one.- The Lookup: Check if the current number is already in your
seenset. - Early Exit (Duplicate Found): If the number is in the set, it means you have encountered it before. Return
trueimmediately. - Update Memory: If the number is not in the set, add it to the
seenset and move on to the next number.
- The Lookup: Check if the current number is already in your
- All Distinct: If the loop finishes and you never triggered the early exit, it means every number was unique. Return
false.
5. Complexity Analysis
- Time Complexity: O(N) — We traverse the array exactly once. Hash Set lookups and insertions operate in O(1) average time, giving us an optimal linear runtime.
- Space Complexity: O(N) — In the worst-case scenario (every number is distinct), we will end up storing all N elements inside our Hash Set. We traded space to gain speed.
6. Code Implementations
Expand the sections below to see the optimal O(N) "Hash Set" implementations across different languages.
View Python Solution
class Solution:
def containsDuplicate(self, nums: List[int]) -> bool:
seen = set()
for num in nums:
# If the number is already on our clipboard, it's a duplicate
if num in seen:
return True
# Otherwise, add it to the clipboard
seen.add(num)
# If we checked every number without returning True, no duplicates exist
return False
# Note: Python also supports a clever 1-liner:
# return len(set(nums)) != len(nums)
View Java Solution
import java.util.HashSet;
import java.util.Set;
class Solution {
public boolean containsDuplicate(int[] nums) {
Set<Integer> seen = new HashSet<>();
for (int num : nums) {
// HashSet.add() returns false if the element is already present
if (!seen.add(num)) {
return true;
}
}
return false;
}
}
View C++ Solution
#include <vector>
#include <unordered_set>
class Solution {
public:
bool containsDuplicate(std::vector<int>& nums) {
std::unordered_set<int> seen;
for (int num : nums) {
// Check if the number is already in the set
if (seen.count(num)) {
return true;
}
// Add the number to the set
seen.insert(num);
}
return false;
}
};
7. Conclusion: You Are Ready
Congratulations, you have just mastered the classic "Contains Duplicate" problem! Understanding how to leverage a Hash Set to reduce O(N²) or O(N log N) time down to O(N) time is one of the most critical realizations in algorithmic problem solving. Recognizing when to spend memory to buy speed is exactly what top-tier engineering managers look for. Keep this "clipboard memory" pattern fresh in your mind—you will use it to solve countless other array and string questions, including the famous Two Sum!