DAY 6 / 30 · WEEK 1

Hash Maps & Sets

Goal of the day

Concept

A hash map is like a coat check counter with numbered tickets. Without it, finding your coat means checking every coat on the rack one by one — O(n). With a ticket number, the attendant jumps straight to your coat — O(1) on average. A hash map does this by running each key through a hash function that turns it into a number, then uses that number to jump directly to a storage slot, instead of scanning.

This is the biggest lever you'll pull all month: almost any "have I seen this before?" or "how many times does X appear?" question can go from an O(n²) nested loop (checking every element against every other element) to a single O(n) pass, by remembering what you've seen in a Map or Set as you go — at the cost of O(n) extra memory. That trade — memory for speed — is the single most common move in interview solutions.

Diagrams

1. Linear scan vs. hash lookup

Is 7 in this collection? 3 9 1 7 ← found (4 checks) Array: check element 1, 2, 3, 4... up to n checks in the worst case. O(n). hash(7) 7 ← found (1 check)

2. Frequency counting

Scanning "abcb" once, building a count as we go a b c b ← seen before, count++ Map after the scan: { a: 1, b: 2, c: 1 } One pass, O(1) work per character — O(n) total, instead of a separate counting pass for every distinct character.

Interactive visualizations

current element not unique yet / no match match found / unique untouched / stored in map

1. Two Sum with a hash map

Press Play or Step to begin.

2. First unique character

Press Play or Step to begin.

The code

// --- Two Sum, the O(n) way (Day 2 showed the O(n²) brute force) ---
function twoSum(nums, target) {
  const seen = new Map(); // value -> index
  for (let i = 0; i < nums.length; i++) {
    const complement = target - nums[i];
    if (seen.has(complement)) return [seen.get(complement), i];
    seen.set(nums[i], i);
  }
  return [-1, -1];
}

// --- Frequency counting ---
function firstUniqChar(s) {
  const counts = new Map();
  for (const ch of s) counts.set(ch, (counts.get(ch) || 0) + 1);
  for (let i = 0; i < s.length; i++) {
    if (counts.get(s[i]) === 1) return i;
  }
  return -1;
}

Line by line:

Dry run: twoSum([3, 2, 4], target = 6)

inums[i]complementIn map?Action
033Noseen.set(3, 0) → {3: 0}
124Noseen.set(2, 1) → {3: 0, 2: 1}
242Yes (index 1)return [1, 2]

Found in one pass, no sorting, works even though the array isn't sorted — the exact case Day 4's two-pointer version couldn't handle directly.

Complexity

OperationTimeSpaceWhy
map.get / set / hasO(1) average, O(n) worst caseO(1) per callWorst case: every key collides into the same slot, degrading to a linear scan.
Two Sum, brute force (Day 2)O(n²)O(1)Check every pair.
Two Sum, hash map (today)O(n)O(n)One entry per number seen so far — genuinely unbounded, since numbers can be arbitrary.
Frequency counting a string/arrayO(n)O(min(n, alphabet size))One count per distinct element. For a fixed small alphabet (e.g. lowercase English letters, 26 possible keys) this is really O(1) space, not O(n) — it only grows with n when the value range itself is unbounded.

Interview corner

How to talk through it out loud: name the trade explicitly — "I'll use a hash map to remember what I've seen, which costs O(n) extra space but drops the time from O(n²) to O(n)." Interviewers want to hear that you know it's a trade, not a free win — mentioning the space cost unprompted is a strong signal.

Practice problems

1. Two Sum (Easy — LeetCode: Two Sum)

Given an array of integers and a target, return the indices of the two numbers that add up to the target. (You wrote the O(n²) brute force for this on Day 2 — now write the O(n) version.)

2. Valid Anagram (Easy — LeetCode: Valid Anagram)

Given two strings, return true if the second is an anagram of the first (same letters, same counts, any order).

3. Group Anagrams (Medium — LeetCode: Group Anagrams)

Given an array of strings, group the anagrams together (any order).

Quiz

1. What's the average time complexity of map.get(key)?

2. Why can hash map lookups degrade to O(n) in the worst case?

3. For general-purpose key/value storage in an interview solution, which is the safer default?

4. In the hash-map Two Sum, what does the map store as each value's mapped data?

5. The frequency-counting pattern is the right fit for problems like: