
Arrays and Hashing is the first topic in the NeetCode 150. Nine problems. I finished it, then re-solved all nine from a blank page to find out what actually stuck.
Not much. That turned out to be the useful part.

They are all the same question
Every problem in this topic asks one thing: have I seen this before?

A set does not store your values in a line. It runs the value through a hash function, and that function returns the address of the one slot where the value would have to live. Go to that slot and look. One place, not n places. Ten numbers or ten million, same cost.
That is the trade: O(n) memory buys O(1) lookups. Every problem below is a decision about whether that trade is worth it.
One caveat, because it is the interview follow-up. O(1) is the average case. Two values can hash to the same slot, and in the pathological case everything lands in one slot and lookup degrades to O(n). Say “average case” when you say O(1).
Group one: asking about a value

Contains Duplicate is the topic in its simplest form.
seen = set()
for n in nums:
if n in seen:
return True
seen.add(n)
Brute force compares every pair, O(n²). This is O(n) time and O(n) space. If you understand why that swap works, you understand the topic.
Valid Anagram asks the same question about counts instead of presence.
return Counter(s) == Counter(t)
Sorting both strings also works, but that is O(n log n) and counting is O(n). Name the sorting solution out loud in an interview, then say why you are not using it. That is worth more than silently producing the fast one.
Two Sum is the first genuinely clever one. You do not need pairs. At each number you already know what its partner must be, target - num, so the real question is whether you have walked past that partner already.

def twoSum(nums, target):
seen = {} # number -> index
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i # AFTER the check, never before
return []
Two things I got wrong, twice. The number is the key, because the number is what you search by. If you are scanning a dictionary’s values to find something, you built it backwards. And the store goes after the check, or a number whose double is the target matches itself and returns [i, i].
Group two: asking about a group
Now the question stops being about single values and starts being about which bucket something belongs in.
Group Anagrams. What key makes all anagrams collapse onto the same entry? Sorted letters.

groups = defaultdict(list)
for w in strs:
groups[tuple(sorted(w))].append(w) # the key is computed, not given
return list(groups.values())
This is the first time the key is something you compute rather than something handed to you. That idea comes back constantly.
Top K Frequent. Counting is a dictionary and you already know how. The interesting part is what comes after.

buckets = [[] for _ in range(len(nums) + 1)]
for num, count in Counter(nums).items():
buckets[count].append(num) # the index IS the count
out = []
for count in range(len(buckets) - 1, 0, -1): # read from the high end down
for num in buckets[count]:
out.append(num)
if len(out) == k:
return out
Sorting the counts is O(n log n) and fine. A heap is O(n log k). Bucket sort is O(n), because a count can never exceed n, so the count can be an index. It is the one place in this topic where the answer is not a hash map. It is an array used as a lookup table, which is the same idea with the hashing step removed.
Valid Sudoku. A cell has to be unique in three groups at once: its row, its column, and its 3×3 box.

box_id = (r // 3, c // 3)
if v in rows[r] or v in cols[c] or v in boxes[box_id]:
return False
rows[r].add(v) # the keys go on the add lines too
cols[c].add(v)
boxes[box_id].add(v)
Three separate memories, not one. My first bug was a single flat seen set for the whole board, which “correctly” rejects a 5 in row 0 and a 5 in row 8.
// 3 collapses indices 0 through 8 into three bands, so (r // 3, c // 3) is the box’s address on a tic tac toe grid. My second bug: I remembered the keys on the three check lines and dropped them on the three add lines. It survives a read-through because the top half looks so obviously right.
Group three: when the hash map is not the answer
Two of the nine are not hashing problems. I think that is deliberate. It stops you pattern matching on the topic name instead of on the problem.
Product of Array Except Self. No division, O(n). Everything except position i is everything left of i times everything right of i.

res = [1] * n
for i in range(1, n):
res[i] = res[i-1] * nums[i-1] # prefixes, built into the answer
suffix = 1
for i in range(n-1, -1, -1):
res[i] *= suffix
suffix *= nums[i] # one running variable, not an array
You do not need two extra arrays. That is O(1) extra space, not counting the output.
Encode and Decode Strings. The strings can contain any character, so any separator you pick can appear inside a word. Stop searching, start counting.

encoded = "".join(f"{len(w)}#{w}" for w in strs)
Decode reads the number, skips the #, then takes exactly that many characters. A # inside a word can never fool you, because you never look for one. You counted.
Still my worst problem, and not for conceptual reasons. My bug is always indentation: the inner loop’s only job is to walk a pointer forward to the #, and I keep putting the lines that use the result inside that loop. Now I ask one question of every line inside a loop: does this happen every step, or once per word?
The one that ties it together
Longest Consecutive Sequence. The longest run of consecutive integers, in O(n). The O(n) is the whole tell, because sorting would make it trivial and sorting is O(n log n).

def longestConsecutive(nums):
num_set = set(nums)
longest = 0
for num in num_set:
if num - 1 not in num_set: # only climb from a run's START
length = 1
while num + length in num_set: # the offset has to move
length += 1
longest = max(longest, length) # outside the while, not inside
return longest
That if is the best line in the topic. Without it the code still returns the right answer, it just quietly becomes O(n²), which is the worst kind of bug because nothing fails.
The complexity argument is worth being able to say out loud, because a while inside a for looks quadratic and is not. Each number is climbed only as part of the one run it belongs to, and each run is climbed once, from its start. Every number is touched at most twice.
Both of my bugs here are marked in the comments. num + 1 checks the same value forever. max() inside the while means a run of length 1 never gets recorded.
What I would tell myself on problem one

Learn why a set is O(1) before you use it nine times. The moment I understood hashing as “compute the address, go there,” I could tell which problems it fit without guessing.
Write the brute force even when you know the answer. Every clever solution here is the brute force with one wasteful step removed. Two Sum removes the search for the partner. Longest Consecutive removes the re-walking of runs. Name the waste and you can derive the fix instead of trying to remember it.
The key is the thing you search by. Two Sum, Group Anagrams and Valid Sudoku are one lesson in three costumes.
Most of my bugs were not algorithmic. A flipped dictionary. A missing key on an add line. An update inside a loop that belonged after it. An offset that never moved. “I got the problem wrong” is not fixable. “I write seen[num] = i backwards under pressure” is.
Next, and a question for you
Two Pointers is next. This is the first post in a series working through the NeetCode 150, and after this one I am grouping topics rather than writing one post per box on the roadmap, because some of these ideas only make sense sitting next to each other.
If you are also grinding toward a Summer 2027 internship, I want to hear which problem is your recurring one. Not the hardest problem you have seen. The one where you know the idea cold and still fumble the same specific line every single time. Mine is Encode and Decode, and it is always the indentation. Leave it below and I will probably end up writing about it.
Discover more from Sarah Rose Hassan
Subscribe to get the latest posts sent to your email.
