Pattern 01 of 20

Arrays & Hashing

Trade memory for speed: remember what you have seen in a hash map or set.

When to use it

  • You need to find pairs, duplicates or counts in one pass
  • A nested loop compares every element with every other
  • Grouping items by a key (an anagram signature, a frequency)

The idea

Most brute-force array problems ask the same question again and again: have I seen this value before? A hash map answers it in constant time, so one pass with a lookup replaces a pass inside a pass.

Typical cost O(n) time, O(n) extra space.

How it works

Think of a hash map as a memory you can query in constant time. Almost every brute-force array solution repeats one expensive question inside a loop: is there an earlier element that completes this one? Storing what you have already seen turns that inner scan into a single lookup.

It works because the question can be phrased as an exact key. Pair sums become 'have I seen target minus x', duplicates become 'is x already in the set', and grouping becomes 'which bucket does this key belong to'. Once the question is a key, the hash structure answers it without caring how many items came before.

The pattern hides behind words like count, group, frequency, first unique, or 'in one pass'. It also hides in prefix sums: a subarray summing to k is just two prefix sums that differ by k, which is the pair-sum lookup again.

The real skill is choosing the key. A sorted string, a tuple of character counts, a running sum, a remainder modulo k: the right signature collapses many different-looking inputs into one bucket.

How to attack it

  1. 1Write the brute force and name the question the inner loop keeps asking.
  2. 2Rephrase that question as a lookup on an exact key.
  3. 3Decide what the map stores per key: a boolean, a count, an index, or a list.
  4. 4Decide the order: look up before inserting the current element, or after.
  5. 5Handle the empty input and repeated values, then confirm one pass is enough.

Template

A skeleton to adapt, not a solution to paste. Write it from memory a few times.

def one_pass_lookup(nums, target):
    # Maps a value (or a derived key) to what we need later: here, its index.
    seen = {}
    for i, x in enumerate(nums):
        need = target - x  # the key that would complete the current element
        if need in seen:
            return [seen[need], i]
        # Insert AFTER the lookup so an element never pairs with itself.
        seen[x] = i
    return []


def group_by_signature(items):
    groups = {}
    for item in items:
        key = "".join(sorted(item))  # choose a signature shared by the group
        groups.setdefault(key, []).append(item)
    return list(groups.values())

Variants

Complement lookup
Store each value and look up the partner that would complete it. The base of every pair-sum question.
Frequency counting
Count occurrences, then read the counts: duplicates, majority element, first unique character, anagram checks.
Grouping by signature
Map each item to a canonical key so equivalent items land in one bucket. The key design is the whole problem.
Prefix sum plus map
Store how often each running sum has occurred; a subarray summing to k exists when sum minus k was seen before. Seed the map with sum 0.
Bucket by value range
When values are bounded, an array indexed by value replaces the map and makes counting sort or top-k by frequency linear.

Pitfalls

  • Inserting the current element before looking it up, so it pairs with itself.
  • Forgetting to seed a prefix-sum map with {0: 1}, which misses subarrays that start at index 0.
  • Using a mutable list as a dictionary key in Python, or an array as a Map key in JavaScript (compared by reference, never equal).
  • Overwriting an index on duplicates when the problem needs the first occurrence.
  • Assuming the map's iteration order is sorted; it is insertion order at best.

What it costs

OperationCost
Hash map insert / lookupO(1) average, O(n) worst case
One pass with lookupsO(n) time, O(n) space
Grouping by sorted-string keyO(n · k log k) for n strings of length k
Grouping by count tupleO(n · k) with a fixed alphabet
Brute force it replacesO(n²) time, O(1) space

61 Arrays & Hashing problems

Easiest first. Problems marked Free can be solved without Pro.

  1. 1Pair With Target SumFreeEasy
  2. 2Duplicate Badge ScanFreeEasy
  3. 3Same Letters, New OrderFreeEasy
  4. 4First Lone CharacterEasy
  5. 5Running Ledger TotalsEasy
  6. 6Balance Point IndexEasy
  7. 7Letter Cipher ConsistencyEasy
  8. 8Clip Letters Into a NoteEasy
  9. 9Shared Values, SortedEasy
  10. 10Majority Ballot WinnerEasy
  11. 11Thin Out a Sorted LogEasy
  12. 12Merge Into the Reserved TailEasy
  13. 13The Missing BadgeEasy
  14. 14Sorted Before the TurnEasy
  15. 15Expand Count-Value PairsEasy
  16. 16Biggest Value AheadEasy
  17. 17The Doubled and the LostEasy
  18. 18Run-Length LabelEasy
  19. 19Unchain the XOR LogEasy
  20. 20Every Vanished NumberEasy
  21. 21Bundle Anagram FamiliesMedium
  22. 22Most Frequent Values, RankedMedium
  23. 23Product of All OthersMedium
  24. 24Longest Unbroken RunMedium
  25. 25Count Windows Summing to KMedium
  26. 26Range Sum QueriesMedium
  27. 27Longest Balanced Binary StretchMedium
  28. 28Count Sums Divisible by KMedium
  29. 29Sudoku Board AuditMedium
  30. 30Four Lists to ZeroMedium
  31. 31Stretch Summing to a MultipleMedium
  32. 32Longest Stretch Summing to KMedium
  33. 33Order Letters by FrequencyMedium
  34. 34Fewest Bricks CrossedMedium
  35. 35Shortest Trim for a Divisible TotalMedium
  36. 36Rotate the CarouselMedium
  37. 37Riffle the Deck in PlaceMedium
  38. 38Alternate Gains and LossesMedium
  39. 39Over a Third of the VoteMedium
  40. 40Unpack a Length-Prefixed StreamMedium
  41. 41Split an Escaped RecordMedium
  42. 42The Repeated TicketMedium
  43. 43Letter at Position K of the TapeMedium
  44. 44Values Seen TwiceMedium
  45. 45Values Already HomeMedium
  46. 46Smallest Left Block Without CrossingsMedium
  47. 47Splits That Share a LeaderMedium
  48. 48Follow the Index TableMedium
  49. 49Fewest Swaps to Order a PermutationMedium
  50. 50Smallest Absent PositiveHard
  51. 51Grid Blocks Summing to TargetHard
  52. 52Palindrome-Ready SubstringsHard
  53. 53Median-Anchored StretchesHard
  54. 54Palindrome Word PairsHard
  55. 55Chunk Concatenation StartsHard
  56. 56Earliest Smallest RotationHard
  57. 57Most Blocks That Sort IndependentlyHard
  58. 58Best Rotation for the ScoreboardHard
  59. 59Widest Gap in Sorted OrderHard
  60. 60Seat Every Pair TogetherHard
  61. 61Smaller Values DownstreamHard

Solve them in the browser, in Python or JavaScript.