Arrays & Hashing: The Interview Patterns You Must Know
- arrays
- hashing
- coding-interview
- dsa
- typescript
- algorithms
If I had to bet on what your next coding interview opens with, I'd put money on an array problem that's secretly a hashing problem. They're everywhere. Two-sum, group anagrams, subarray sums, "find the duplicate." Different clothes, same skeleton underneath.
The engineers who breeze through these aren't faster typists. They've just learned to see the hash map hiding inside the array question. Once you see it, you can't unsee it, and a whole category of problems stops being scary.
This is the second article in the Senior Engineer Handbook series. Last time we covered how to approach interviews. Now we get specific.
Why hashing shows up so often
Most array problems are slow for one reason: you're searching. "Have I seen this value before?" "Does its complement exist?" "How many times has this appeared?" The naive answer to every one of those is a nested loop: scan the array again for each element. That's O(n²), and O(n²) is the thing the interviewer is quietly waiting for you to kill.
A hash map turns "search the whole array" into "check one key." O(n) lookups collapse to O(1). That single move is the difference between the brute-force answer and the one that gets you a callback.
So when a problem involves searching, counting, or matching inside an array, my first instinct is: what would I store in a map to make the lookup instant?
Pattern 1: complement lookup
The classic. You're looking for two things that combine to a target. Instead of checking every pair, store what you've seen and ask whether the piece you need is already there.
function twoSum(nums: number[], target: number): [number, number] | null {
const seen = new Map<number, number>(); // value -> index
for (let i = 0; i < nums.length; i++) {
const need = target - nums[i];
if (seen.has(need)) return [seen.get(need)!, i];
seen.set(nums[i], i);
}
return null;
}
The mental model: as I walk the array, I keep a record of everything behind me, so when I land on a number I can instantly ask "did its partner already go by?" No second loop. One pass.
This same shape solves far more than two-sum. "Find if any two elements differ by k." "Does a pair exist that sums to a value?" Same skeleton, different arithmetic on the key.
Pattern 2: frequency counting
The second workhorse. Whenever a problem cares about how many times something appears (most frequent element, first non-repeating character, "can these two strings be anagrams"), you're building a frequency map.
function firstUniqueChar(s: string): number {
const count = new Map<string, number>();
for (const ch of s) count.set(ch, (count.get(ch) ?? 0) + 1);
for (let i = 0; i < s.length; i++) {
if (count.get(s[i]) === 1) return i;
}
return -1;
}
Two passes, both O(n). First pass tallies, second pass reads the tally. I like this one in interviews because it's easy to narrate cleanly: "count everything, then find the first thing with a count of one." The interviewer follows you the whole way.
A tell for anagram problems specifically: two strings are anagrams if their frequency maps are identical. You don't need to sort: sorting is O(n log n) and counting is O(n). If you reach for .sort() here, expect the interviewer to ask "can you do better?"
Pattern 3: grouping by a computed key
This one trips people up because the key isn't the value itself. It's something you derive from it. Group anagrams is the poster child: the key is the sorted version of each word, and all words sharing that key belong together.
function groupAnagrams(words: string[]): string[][] {
const groups = new Map<string, string[]>();
for (const word of words) {
// Words that are anagrams collapse to the same sorted key.
const key = word.split('').sort().join('');
const bucket = groups.get(key) ?? [];
bucket.push(word);
groups.set(key, bucket);
}
return [...groups.values()];
}
Worth saying out loud: "I need a signature that's the same for every anagram and different for everything else." Sorted letters is one such signature. A 26-length letter-count array is another (and faster). Naming that idea ("I need a canonical key") is exactly the kind of reasoning senior interviews reward.
Pattern 4: prefix sums with a map
Now the one that separates people. "How many subarrays sum to k?" The brute force checks every subarray, which is O(n²). The trick is a running total plus a hash map of totals you've seen.
function subarraySumEqualsK(nums: number[], k: number): number {
const seen = new Map<number, number>([[0, 1]]); // prefixSum -> how many times
let running = 0;
let count = 0;
for (const n of nums) {
running += n;
// If (running - k) appeared before, every such prefix marks a valid subarray end here.
count += seen.get(running - k) ?? 0;
seen.set(running, (seen.get(running) ?? 0) + 1);
}
return count;
}
I won't pretend this one is obvious. It took me a few sittings to really get why running - k is the thing to look up. The idea: if the total up to here is running, and some earlier point had total running - k, then the stretch between them sums to exactly k. The map counts how many such earlier points exist.
If you only memorize one non-trivial pattern from this article, make it this one. Prefix-sum-plus-map shows up constantly and always looks impressive because most people don't see it.
When a hash map is the wrong answer
Reaching for a map reflexively is its own trap, so let me push back on my own advice.
Maps cost memory. If the problem says "solve it in O(1) space," a hash map is off the table and they probably want two pointers or in-place index marking instead. If the array is sorted, a map throws away information you could've used; two pointers or binary search is often cleaner and uses no extra space. And for tiny fixed alphabets (lowercase letters), a plain 26-slot array beats a Map on both speed and clarity.
Part of sounding senior is knowing when not to use the tool you like. If you say "a hash map would work, but since the input's sorted I can do this in O(1) space with two pointers," you've just shown range.
How to recognize which pattern you're in
A quick field guide for the pressure of the moment:
- Looking for pairs/complements that hit a target → complement lookup
- Counting occurrences, or comparing multisets/anagrams → frequency map
- Bucketing items that share a derived property → group by computed key
- Anything about contiguous subarray sums or counts → prefix sum + map
- Sorted input, or an O(1)-space constraint → step back, consider two pointers instead
Say the category out loud when you spot it. "This is a frequency-counting problem" tells the interviewer you've mapped it to a known shape, and it steadies your own hands.
Next in the series, we leave hashing behind for the two techniques that dominate sorted-array and substring problems: two pointers and the sliding window.
Key takeaways
- Most slow array solutions are slow because they search; a hash map turns O(n) searches into O(1) lookups.
- Four patterns cover the majority of interview questions: complement lookup, frequency counting, grouping by a computed key, and prefix sum with a map.
- For anagrams, compare frequency maps instead of sorting; O(n) beats O(n log n).
- Prefix-sum-plus-map (subarrays summing to k) is the highest-value non-obvious pattern; learn it cold.
- A hash map is the wrong choice when space must be O(1) or the array is already sorted; reach for two pointers there.
Frequently asked questions
When should I use a hash map in an array problem
When you're searching, counting, or matching: anything where the naive answer is a nested loop scanning the array again. A map makes those lookups O(1) and drops the overall time from O(n²) to O(n).
Why not just sort the array instead of hashing
Sorting is O(n log n) and destroys the original order. Hashing is O(n) and preserves order. Sort only when the problem genuinely needs ordering or when a sorted array unlocks two pointers with O(1) space.
What's the prefix sum pattern and when do I use it
Keep a running total and store each total in a map. For "count subarrays summing to k," look up `running - k` to find where valid subarrays start. Use it for any contiguous-subarray sum or count question.
How do I check if two strings are anagrams efficiently
Build a frequency count for each and compare, or use a single 26-length array of letter counts. Both are O(n), faster than sorting both strings.
Are hash map solutions always the best
No. They cost memory. If the problem demands O(1) space or the input is sorted, two pointers or binary search is usually cleaner and lighter.
Further reading
Explore more on

About the author
I'm Aman Kumar Singh, a software engineer in Noida, India building scalable full-stack products with React, Next.js, Node.js, NestJS, PostgreSQL, Redis, and AWS. I write about backend engineering, distributed systems, and system design.