You're solving "Contains Duplicate." You write:
seen = {}
for num in nums:
if num in seen:
return True
seen[num] = TrueIt works. But you're using a hash map when a set would be cleaner, clearer, and more efficient.
This is a common beginner mistake: defaulting to hash maps when sets are sufficient.
This guide gives you the simple decision rule for choosing between hash maps and sets.
The Core Difference
Hash Set
Stores: Keys only (presence/absence)
seen = set()
seen.add(5)
5 in seen # TrueUse when: You only care if something exists.
Hash Map
Stores: Key-value pairs
seen = {}
seen[5] = "some value"
5 in seen # True
seen[5] # "some value"Use when: You need associated data with each key.
The Decision Rule
Do you need to store anything besides the key?
├─ Yes → Hash map
└─ No → Hash setThat's it. Let's see examples.
When to Use Hash Set
Example 1: Contains Duplicate (LeetCode 217)
Problem: Check if array contains any duplicates.
❌ Hash map (overkill):
def containsDuplicate(nums):
seen = {}
for num in nums:
if num in seen:
return True
seen[num] = True # Don't need this value!
return False✅ Hash set (correct):
def containsDuplicate(nums):
seen = set()
for num in nums:
if num in seen:
return True
seen.add(num)
return False
# Or even simpler
def containsDuplicate(nums):
return len(nums) != len(set(nums))Why set is better:
- Clearer intent: "I only care about presence"
- Simpler API:
add()vs[key] = value - Slightly more memory efficient
Example 2: Intersection of Two Arrays (LeetCode 349)
Problem: Find unique elements that appear in both arrays.
✅ Hash set:
def intersection(nums1, nums2):
set1 = set(nums1)
set2 = set(nums2)
return list(set1 & set2) # Set intersection
# Or
def intersection(nums1, nums2):
set1 = set(nums1)
return [num for num in set2 if num in set1]Why set is better:
- Only need presence, not counts
- Set operations (
&,|,-) are natural - No need for values
Example 3: Happy Number (LeetCode 202)
Problem: Detect cycle in number transformation.
✅ Hash set:
def isHappy(n):
seen = set()
while n != 1:
if n in seen:
return False # Cycle detected
seen.add(n)
n = sum(int(d)**2 for d in str(n))
return TrueWhy set is better:
- Only checking if we've seen this number before
- Don't need to store any associated data
When to Use Hash Map
Example 1: Two Sum (LeetCode 1)
Problem: Find two numbers that sum to target, return indices.
✅ Hash map (need indices):
def twoSum(nums, target):
seen = {} # Can't use set - need to store indices!
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i # Store index as value
return []Why map is needed:
- Need to store index (value) for each number (key)
- Set can't store this association
Example 2: First Unique Character (LeetCode 387)
Problem: Find first non-repeating character.
✅ Hash map (need counts):
from collections import Counter
def firstUniqChar(s):
freq = Counter(s) # Map: char → count
for i, char in enumerate(s):
if freq[char] == 1:
return i
return -1Why map is needed:
- Need to store count (value) for each character (key)
- Set can only tell us presence, not frequency
Example 3: Group Anagrams (LeetCode 49)
Problem: Group words that are anagrams.
✅ Hash map (need to group):
from collections import defaultdict
def groupAnagrams(strs):
groups = defaultdict(list) # Map: key → list of words
for word in strs:
key = ''.join(sorted(word))
groups[key].append(word) # Store list as value
return list(groups.values())Why map is needed:
- Need to store list of words (value) for each pattern (key)
- Set can't store these associations
Comparison Table
| Aspect | Hash Set | Hash Map |
|---|---|---|
| Stores | Keys only | Key-value pairs |
| Purpose | Presence check | Associated data |
| API | add, remove, in | get, set, in |
| Memory | Slightly less | Slightly more |
| Use case | Membership, dedup | Need values |
Common Patterns
Pattern 1: Deduplication → Set
# Remove duplicates
unique = list(set(nums))
# Count unique
count = len(set(nums))Pattern 2: Membership testing → Set
# Check if element exists
allowed = set([1, 2, 3, 4, 5])
if num in allowed:
# ...Pattern 3: Cycle detection → Set
# Detect if we've seen this state before
seen = set()
while state not in seen:
seen.add(state)
state = transform(state)Pattern 4: Frequency counting → Map
# Count occurrences
from collections import Counter
freq = Counter(nums)Pattern 5: Index tracking → Map
# Store positions
index_map = {}
for i, num in enumerate(nums):
index_map[num] = iPattern 6: Grouping → Map
# Group by property
groups = defaultdict(list)
for item in items:
key = compute_key(item)
groups[key].append(item)Common Mistakes
Mistake 1: Using map when set suffices
❌ Wrong:
# Contains duplicate with map
seen = {}
for num in nums:
if num in seen:
return True
seen[num] = True # Unnecessary value✅ Correct:
# Use set
seen = set()
for num in nums:
if num in seen:
return True
seen.add(num)Mistake 2: Using set when you need values
❌ Wrong:
# Two Sum with set - can't store indices!
seen = set()
for i, num in enumerate(nums):
if target - num in seen:
return [?, i] # Where's the other index?
seen.add(num)✅ Correct:
# Use map to store indices
seen = {}
for i, num in enumerate(nums):
if target - num in seen:
return [seen[target - num], i]
seen[num] = iMistake 3: Not using set operations
❌ Verbose:
# Intersection with loops
result = []
set1 = set(nums1)
for num in nums2:
if num in set1:
result.append(num)✅ Pythonic:
# Use set operations
result = list(set(nums1) & set(nums2))Quick Reference
Use Set when you need:
- ✅ Check if element exists
- ✅ Remove duplicates
- ✅ Detect cycles
- ✅ Membership testing
- ✅ Set operations (union, intersection, difference)
Use Map when you need:
- ✅ Count frequencies
- ✅ Store indices/positions
- ✅ Group items
- ✅ Associate data with keys
- ✅ Track metadata per element
Practice Problems
Use Set
- Contains Duplicate (#217) - Presence only
- Happy Number (#202) - Cycle detection
- Intersection of Two Arrays (#349) - Set intersection
- Longest Consecutive Sequence (#128) - Membership
Use Map
- Two Sum (#1) - Need indices
- Group Anagrams (#49) - Need to group
- Top K Frequent Elements (#347) - Need counts
- First Unique Character (#387) - Need frequency
Could use either (but set is cleaner)
- Valid Sudoku (#36) - Presence check
- Word Pattern (#290) - Bidirectional mapping (need map)
Summary
The choice between hash map and set is simple.
The rule:
Need associated values? → Hash map
Only need presence? → Hash setHash set:
- Clearer intent
- Simpler API
- Slightly more efficient
- Use for: presence, dedup, cycles
Hash map:
- Stores key-value pairs
- More flexible
- Use for: counts, indices, grouping
When in doubt: Start with set. If you realize you need values, upgrade to map.
Next steps:
- Master hash map vs other structures
- Learn frequency counter pattern
- Study the complete hash map guide
Choose the right tool. Keep it simple.
Want to Practice LeetCode Smarter?
LeetCopilot is a free browser extension that enhances your LeetCode practice with AI-powered hints, personalized study notes, and realistic mock interviews — all designed to accelerate your coding interview preparation.
Also compatible with Edge, Brave, and Opera
