Problem-solving patterns with hash maps

Frequency counting, complement lookup and grouping by key — three patterns that cover most map questions.

Most "make this faster" answers reduce to one of three uses of a hash map.

1. Frequency counting

function counts(items) {
  const seen = new Map();
  for (const item of items) seen.set(item, (seen.get(item) ?? 0) + 1);
  return seen;
}

Anagram checks, "first non-repeating character", "top k frequent", "majority element" — all frequency maps. Combine with a heap or bucket sort for the top-k variants.

2. Complement lookup — remember what you have seen

The famous two-sum, in one pass:

function twoSum(items, target) {
  const seen = new Map();          // value → index

  for (let i = 0; i < items.length; i++) {
    const need = target - items[i];
    if (seen.has(need)) return [seen.get(need), i];
    seen.set(items[i], i);
  }

  return null;
}

O(n) instead of O(n²), and unlike the two-pointer version it needs no sorting, so it returns original indices.

The generalisation is the prefix-sum map from chapter 3: as you scan, ask "have I already seen the thing that would complete an answer here?"

3. Grouping by a derived key

The trick is choosing a key that makes equivalent things collide on purpose:

function groupAnagrams(words) {
  const groups = new Map();

  for (const word of words) {
    const key = [...word].sort().join('');       // anagrams share this key
    if (!groups.has(key)) groups.set(key, []);
    groups.get(key).push(word);
  }

  return [...groups.values()];
}

Other useful derived keys: row - col and row + col for chessboard diagonals, a normalised shape for isomorphic strings, a sorted tuple for equivalent sets.

Choosing the right map in JavaScript

Need Use
Any key type, size, insertion order Map
Membership only Set
String keys, JSON-friendly plain object
Keys that should not prevent garbage collection WeakMap

Prefer Map over an object for dynamic keys: no prototype surprises with keys like __proto__ or constructor, and size is O(1).

The cost you are accepting

Every one of these buys time with O(n) memory. Say so when you present the solution — "O(n) time, O(n) space, trading memory for the second pass" is the complete sentence.