Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Arrays & Hashing  ›  Lesson

Counting With Maps: Same Letters, Top Items

Valid Anagram 13 minWhen order does not matter, two collections match exactly when every item appears the same number of times, so a dictionary of counts answers both matching and most-frequent questions.

Counting With Maps: Same Letters, Top Items

In a word game, two players each build a word from a pile of letter tiles, and a referee must check whether both words used exactly the same tiles. The letters can be in any order, but every tile has to be accounted for. When order stops mattering, the only thing left to compare is how many of each.

The rule

When order doesn't matter, compare counts, not sequences.

A dictionary from item to count captures everything about a collection except its order. Python's Counter builds one in a single call, and two Counters compare equal exactly when every item appears the same number of times in both:

from collections import Counter

def same_tiles(a, b):
    if len(a) != len(b):
        return False                  # different sizes can never match
    return Counter(a) == Counter(b)

Sorting both words and comparing (sorted(a) == sorted(b)) also works, because sorting puts equal letters together. It costs n log n instead of n, which is usually fine; counting is simply the more direct statement of the idea.

Counting is also the first half of every "most frequent" question. To find the k most common tags on a blog, count them, then pick the biggest counts:

tags = ["py", "js", "py", "go", "py", "js", "rs"]
Counter(tags).most_common(2)          # [('py', 3), ('js', 2)]

When interviewers want better than sorting the counts, use buckets: a count can never exceed the number of items n, so make a list of n + 1 buckets, drop each tag into the bucket for its count, and read buckets from the top down. That is one pass to count and one pass to read.

The shortcut

Keep one tally, up for the first word and down for the second. If every count lands back on zero, the tiles matched. You never need two dictionaries, and you can stop the moment a count goes below zero, because the second word just used a tile the first never had.

Do "cider" and "cried" use the same tiles?Step 1 of 4
  1. Quick reject

    Both have 5 letters, so keep going. Different lengths would have ended it here.

The trap is comparing sets. set("aab") == set("abb") is True, because a set records only which letters appear, not how many times. Counting keeps the "how many".

Drills

Answer fast — trust the rule.

quick drill

What is Counter("aab") == Counter("abb")?

quick drill

Which check can answer "not the same tiles" before any counting at all?

quick drill

What does Counter(["py", "js", "py", "go", "py", "js", "rs"]).most_common(2) return?

quick drill

In the bucket trick for the k most frequent items, why can each count be used as a list index?

Remember

  • When order doesn't matter, compare counts, not sequences.
  • Shortcut: one tally, up for the first, down for the second; all zeros means a match.
  • Trap: comparing sets, which forget how many times each item appears.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainDo the receipts match?

Two shop receipts list items in different orders, and an item can appear more than once. Explain how you would decide whether they contain exactly the same items the same number of times, and why set(a) == set(b) would give the wrong answer for some receipts. Give an example.