Hash Map & Set 101
Fundamental · 4 chapters · 8 min read · Turn slow nested loops into one pass by remembering what you have already seen.
Practise this in the app All guides
What hashing buys you
Constant-time lookup
A hash map stores key-value pairs and finds a key in O(1) time on average. A hash set is the same thing without values: it answers "have I seen this before?" in O(1). In Python these are dict and set, with helpers in collections such as Counter and defaultdict.
The trade is memory for time. A brute-force solution that compares every pair costs O(n²); storing what you have seen in a map usually brings it down to O(n) time with O(n) extra space. In most interviews that trade is exactly what is expected.
Signals in a problem statement
- "Find two elements that ..." or "does a pair exist" — store each element and look up its complement.
- "Duplicate", "unique", "distinct", "first repeating" — a set.
- "Count", "frequency", "most common", "anagram" — a counter.
- "Group by" some property — a map from a canonical key to a list.
- "Within distance k" — a map from value to its last index.
- "Map one string onto another" (isomorphic, word pattern) — two maps, one in each direction.
- "Longest consecutive run" in an unsorted array in O(n) — a set and a clever starting condition.
What can be a key
Keys must be hashable: numbers, strings, tuples of hashable things, and frozenset. Lists and dicts cannot be keys. When you need a list as a key, convert it to a tuple; for example, a 26-length tuple of letter counts is a perfect key for grouping anagrams.
The mental model
Walk the input once. At each step, ask: "What do I need to know about the elements before this one?" Store exactly that in the map, keyed by whatever you will look it up with later.
Core patterns with templates
1. Seen-before lookup (complement)
def two_sum(nums, target):
seen = {}
for i, x in enumerate(nums):
if target - x in seen:
return [seen[target - x], i]
seen[x] = i
return []
Insert after checking so an element is never paired with itself.
2. Frequency counting
from collections import Counter
def can_construct(note, magazine):
have = Counter(magazine)
for ch in note:
if have[ch] == 0:
return False
have[ch] -= 1
return True
3. Group by canonical key
from collections import defaultdict
def group_anagrams(words):
groups = defaultdict(list)
for w in words:
groups["".join(sorted(w))].append(w)
return list(groups.values())
For lowercase words, a tuple of 26 counts avoids the sort and makes each key O(length).
4. Last index within a window
def nearby_duplicate(nums, k):
last = {}
for i, x in enumerate(nums):
if x in last and i - last[x] <= k:
return True
last[x] = i
return False
5. Start only at the beginning of a run
def longest_consecutive(nums):
s = set(nums)
best = 0
for x in s:
if x - 1 not in s:
y = x
while y + 1 in s:
y += 1
best = max(best, y - x + 1)
return best
Each number is visited by the inner loop at most once, so the total is O(n). Example: [100, 4, 200, 1, 3, 2] starts runs only at 1, 100 and 200, giving 4.
6. Bijection with two maps
For isomorphic strings, keep s_to_t and t_to_s. A mismatch in either direction means the answer is false.
Complexity, mistakes and edge cases
Complexity
| Operation | Average | Worst case |
|---|---|---|
| insert, lookup, delete | O(1) | O(n) with heavy collisions |
| iterate all keys | O(n) | O(n) |
Counter(s) | O(len(s)) |
Interviewers accept "O(1) average" for hash operations. If asked about the worst case, mention collisions, and that languages randomise hash seeds partly to defend against crafted inputs.
Common mistakes
- Using a list for membership.
if x in my_listis O(n); use a set. - Unhashable keys. Convert lists to tuples before using them as keys.
- Missing the reverse mapping. For "one-to-one" questions, a single map lets
"ab" -> "cc"slip through. - Inserting before checking. In complement problems this can pair an element with itself.
- Relying on dictionary order for logic. Python dicts keep insertion order, but do not build correctness on that unless you say so explicitly.
- Forgetting
Counterreturns 0 for missing keys while a plaindictraisesKeyError. Use.get(k, 0)with plain dicts.
Edge cases
Empty input, a single element, all elements identical, negative numbers and zero, case sensitivity in strings, and k = 0 in window questions. For anagram and frequency questions, ask whether the alphabet is only lowercase English letters; a fixed alphabet lets you use an array of size 26 and claim O(1) extra space.
Comparing frequency shapes
Some questions ask whether one string can be turned into another by swapping characters or relabelling them. The answer often depends only on two facts: both strings use the same set of characters, and the sorted list of counts is the same. Spotting that you can compare sorted(Counter(a).values()) with sorted(Counter(b).values()) is a very common "aha" moment.
Variations and practise
Common twists
- Sliding window plus map. Many substring questions combine a moving window with a counter of characters inside it. You will meet this pattern again in the Sliding Window card.
- Prefix sums plus map. "Count subarrays with sum k" stores how often each running sum has appeared. That is the heart of the Prefix Sum card.
- Ordered requirements. If the interviewer asks for keys in sorted order, mention that a hash map does not give you that; you would sort the keys at the end (O(k log k)) or use a balanced tree in languages that have one.
- Memory limits. "What if the data does not fit in memory?" Talk about hashing keys into buckets on disk, or a Bloom filter for approximate membership.
- Designing your own hash map. Occasionally asked: an array of buckets, each a list of
(key, value)pairs, with resizing when the load factor grows.
How to talk through it
Say what the map stores in one sentence: "a map from value to the latest index where it appeared". If you cannot phrase it that clearly, the code will probably be muddled too.
Practise
The problems below start with direct counting and lookup, then move to grouping, bijections, and the consecutive-run trick. For each one, before writing code, name the key and the value of your map. Aim to finish the Easy ones in under ten minutes and explain your space usage on every Medium.
Practise
Easy
- 367. Ransom Note
- 368. Isomorphic Strings
- 369. Contains Duplicate II
- 375. First Badge Scanned Twice
- 379. Sum of Lone Sensor Readings
- 380. Two Gifts for an Exact Budget
- 381. Songs on Both Playlists
- 382. Shared Stock with Repeats
- 383. First Character Without a Twin
- 384. Counting Rare Stones
- 385. Words Typed with One Hand
- 386. Duplicated and Missing Ticket
- 387. Sentence Uses Every Letter
- 388. Election Winner by Votes
- 389. Value Equal to Its Count
- 390. All Occurrence Counts Distinct
- 391. Matching Pairs in a Row
- 392. Final Stop of a Route
- 393. Distinct Mail Inboxes
- 394. Walker Revisits a Spot
- 395. Words Lonely Across Two Notes
- 396. Words Buildable from Tiles
- 397. Extra Letter Slipped In
- 398. Digit-Square Chain Reaches One
- 399. Best Shared Pick
- 400. Permutation of the Range
- 401. Dense Score Ranks
- 402. Longest Neighbor-Value Selection
- 403. Decode with a Key Phrase
- 404. Pair Up Equal Values
- 405. Copies of a Word from Letters
- 406. Top Word Not Banned
- 407. Present in At Least Two Lists
- 408. Isolated Values
- 409. Letters in Every Word
- 410. Distinct Encodings
- 411. Equalize by One Removal
- 412. Drop Repeated Nodes
- 413. Pair Sum in a Search Tree
- 414. Most Common Values in a Tree
- 415. Score a Code Guess
- 416. Widest Same-Letter Gap
- 417. Busiest Grid Line
- 418. Values with Reversed Twins
- 419. Equal-Value Groups
- 420. The Trusted Host
- 421. Longest Palindrome from Tiles
- 422. Shortest Covering Word
- 423. Largest Digit-Sum Groups
- 424. One Swap Away
- 425. Matching Tile Pairs
- 426. Pairs at a Fixed Distance
- 427. Evenly Spaced Triples
- 428. Prefix and Suffix Variety Gap
- 429. Odd One Out by Letter Gaps
- 431. Self-Describing Digits
- 433. Build a Chained Bucket Map
Medium
- 370. Group Anagrams
- 371. Longest Consecutive Sequence
- 372. Determine if Two Strings Are Close
- 376. Pairs with Sum Divisible by K
- 377. Four-List Zero Tuples
- 378. Top Played Tracks
- 430. Longest Uniform Run Seen Three Times
- 432. Longest Equal Run After Deletions
- 434. Echo Nodes in a Tree
- 435. Rearrangeable Palindrome Paths
- 436. Commonest Subtree Totals
- 437. Combination Lock Escape
- 438. Sort by Letter Frequency
- 439. Make Letter Counts Close
- 440. Longest Stretch Without Repeats
- 441. Exact-Count Substrings
- 442. Longest Run Using at Most K Colors
- 443. Distinct Subarrays with Few Multiples
- 444. Scrambled Word Hidden in Text
- 445. One-Swap Number Twins
- 446. Subarrays with Sum Divisible by K
- 447. Longest Subarray Summing to K
- 448. Longest Strong Stretch
- 449. Matching Row and Column Pairs
- 450. Least-Recent Eviction Cache
- 451. Versioned Value Store
- 452. Snapshot Ledger
- 453. Trip Time Averages
- 454. Message Rate Limiter
- 455. Fewest Bricks Cut
- 456. Equidistant Point Triples
- 457. Longest Fixed-Step Chain
- 458. Longest Evenly Stepped Subsequence
- 459. Longest Self-Summing Subsequence
- 460. Repeated Subtree Shapes
- 461. Downward Path Sums
- 462. Tree Columns Top to Bottom
- 463. Drop Zero-Sum Runs
- 464. Linked Groups of Picked Values
- 465. Split Cards into Consecutive Runs
- 467. Pair Every Value with Its Double
- 468. Edits to Make an Anagram
- 469. Universal Words
- 470. Group by Letter Shift
- 471. Even and Odd Swap Classes
- 472. Repeated Gene Fragments
- 474. Longest Even-Vowel Stretch
- 476. Near-Palindromic Substrings
- 478. Balanced Tri-Color Subarrays
- 480. Shortest Cut for Divisibility
- 482. Pairs with a Target XOR
- 484. Subarrays XOR-ing to K
- 486. Best Distinct Window Sum
- 488. Longest Uniform Run After Edits
- 490. Number Grid Consistency
- 492. Distinct Island Shapes
- 494. Equal Product Quadruples
- 495. Mirrored Balance Pairs
- 496. Same-Shape Frame Pairs
- 497. Fewest Rounds of Chores
- 498. Deletions for Unique Counts
- 499. Fewest Repeat-Free Pieces
- 500. Chunks by Last Sighting
- 501. Minimum Flock Size
- 502. Shortest All-Ones Multiple
- 503. Fraction as Decimal Text
- 504. Palindrome from Two-Letter Blocks
- 505. Even Variety Splits
- 506. Players by Losses
- 507. Square Corner Counter
- 508. Longest Substring with Each Letter K+ Times
- 509. Same Alphabet Pairs
- 510. Best Equal Digit-Sum Pair
- 511. Earliest Dominant Split
- 512. Shared Prefix Counts
- 513. Twin Distance Totals
- 514. Pair Counter with Updates
- 515. Container Index Lookup
- 516. Scoreboard Top K
- 517. Frequency Tracker
- 518. Duplicate Content Groups
- 519. Domain Visit Totals
- 520. Flagged Transactions
- 521. Frequent Badge Users
- 522. Longest Stepwise-Built Word
- 523. Shorten Words to Roots
- 524. One-Edit Dictionary Matches
- 525. Most Frequent Bounded Substring
- 526. Smallest Clean Card Back
- 527. Longest Square Chain
- 528. Power-of-Two Pairs
- 529. Distinct Three-Letter Palindromes
- 530. Mirror Line Check
- 531. Largest Union After Halving
- 532. Form Groups by Requested Size
- 533. Active Minute Histogram
- 534. Uniform Rows After Column Flips
- 535. Anti-Diagonal Order of Ragged Rows
- 536. Fewest Kinds to Halve
- 537. Color Variety After Each Paint
- 538. Range Value Counts
- 539. Best Endpoint-Gap Subarray Sum
- 540. Balance Variety with One Swap
- 541. Subarrays with Many Twins
- 542. Distinct Subarray ORs
- 543. Edits for an Alternating Pattern
- 544. Most Disjoint Target Subarrays
- 545. Distinct Values per Window
- 546. Longest Shared Segment
- 547. Right-Angle Cell Triples
- 548. Robot Farthest Reach
- 549. Garden Lights After Many Nights
- 550. Two Disjoint Target Subarrays
- 551. Concatenation Pairs for a Target
- 552. Shortest Unique Snippet per Word
- 553. Best Pair XOR
- 554. Longest Growing Word Chain
- 555. Restore a Sequence from Neighbor Pairs
- 556. Mismatches After Allowed Swaps
- 557. Expiring Cache
- 558. Wraparound Alphabet Substrings
- 603. Exact-K Occurrence Subarrays
Hard
- 373. Substring with Concatenation of All Words
- 374. Palindrome Pairs
- 466. Longest Repeated Snippet
- 473. Counter with Constant-Time Extremes
- 475. Pop the Most Popular
- 477. Windows Centered on K
- 479. Longest Shared Route
- 481. First Substring with a Given Fingerprint
- 483. Prefix Score Totals
- 485. Islands up to Symmetry
- 487. Sum of Solo-Letter Counts
- 489. Count Arithmetic Subsequences
- 491. Balanced Vowel Substrings, Divisible
- 493. Nearby Close Values
- 559. Distinct Doubled Substrings
- 560. Longest Evenable Prefix
- 561. Longest Shufflable Palindrome of Digits
- 562. Fewest Changes to a Consecutive Run
- 563. Subarrays with More Ones than Zeros
- 564. Fewest Swaps to Match
- 565. Sliding Tile Moves
- 566. Hop Across the River
- 567. Tally Elements in a Formula
- 568. Most Sortable Chunks
- 569. Puzzle Word Counts
- 570. Distinct Non-Empty Subsequences
- 571. Tightest Range Across Lists
- 572. Seat Swaps for Partners
- 573. Most Mirror Chunks
- 574. Shortest Front-Padded Palindrome
- 575. Border Word Pairs
- 576. Grid Paths with a Target XOR
- 577. Split Halves Closest
- 578. Tallest Even Pillars
- 579. Complete Letter Substrings
- 580. Total Sorted Gaps
- 581. Count Clean Partitions
- 582. Two-Swap Number Twins
- 583. Best-Beauty Letter Subsequences
- 584. Square Chain Permutations
- 585. Build Word Squares
- 586. Compound Words
- 587. Fewest Label Sheets
- 588. Palindromic Tree Paths
- 589. Mode of Every Window
- 590. Even-Occurrence Subarrays
- 591. Permutation Subarrays
- 592. Rearrangement Queries
- 593. Distinct Subtree Shapes
- 594. Escape the Blockade
- 595. Scoped Expression Evaluator
- 596. Transactional Key-Value Store
- 597. Multi-Pattern Scramble Counts
- 598. Distinct Palindromic Substrings
- 599. Period Queries
- 600. Largest Repeated Square Block
- 601. Sum of Prefix Match Scores
- 602. Repeats Inside Repeats
- 604. Smallest Missing Value per Subtree