juniorStrings

How do you check if two strings are anagrams?

Updated Feb 20, 2026

Short answer

Count the characters in each string and compare the counts — O(n) time and O(k) space in the alphabet size. The obvious alternative, sorting both strings and comparing, is simpler to write but O(n log n). Both need an early length check, and both require you to decide explicitly how case, whitespace, and Unicode should be treated.

Deep explanation

Python
from collections import Counter
def is_anagram(a, b):
if len(a) != len(b): # cheap rejection before any counting
return False
return Counter(a) == Counter(b)

Or with a single pass and one table, which avoids building two dictionaries:

Python
def is_anagram(a, b):
if len(a) != len(b):
return False
counts = {}
for ch in a:
counts[ch] = counts.get(ch, 0) + 1
for ch in b:
if ch not in counts:
return False
counts[ch] -= 1
if counts[ch] == 0:
del counts[ch]
return not counts
ApproachTimeSpace
Sort bothO(n log n)O(n)
Count charactersO(n)O(k), alphabet size

For a fixed lowercase ASCII alphabet, space is a 26-element array — effectively O(1), and fast enough that the counting version wins decisively at any meaningful size.

The requirements question matters more than the algorithm. "Anagram" is underspecified, and a good answer asks: is it case sensitive? Do spaces and punctuation count? What about Unicode? "Listen" and "Silent" are anagrams to a person but not to a naive comparison.

Unicode is the genuinely hard part. é can be one code point or e plus a combining accent — visually identical, different sequences. Normalising with NFC before comparing handles it. Comparing raw code points will report two identical-looking strings as non-anagrams.

Real-world example

Grouping a word list into anagram sets, using a canonical key:

Python
from collections import defaultdict
def group_anagrams(words):
groups = defaultdict(list)
for w in words:
key = tuple(sorted(w.lower())) # same key for every anagram
groups[key].append(w)
return list(groups.values())
group_anagrams(['eat', 'tea', 'tan', 'ate', 'nat', 'bat'])
# [['eat','tea','ate'], ['tan','nat'], ['bat']]

Sorting each word is O(k log k) in the word length, but it produces a hashable canonical form, so grouping n words is O(n · k log k) overall rather than comparing every pair at O(n²).

Common mistakes

  • - Skipping the length check, doing full O(n) work to reject strings that could never match.
  • - Assuming case insensitivity, or assuming case sensitivity, without asking — the requirement is genuinely ambiguous.
  • - Sorting when counting would do, paying O(n log n) for an O(n) problem.
  • - Ignoring Unicode normalisation, so visually identical strings with different code-point sequences compare unequal.
  • - Comparing sums or products of character codes as a shortcut — different multisets can collide, producing false positives.

Follow-up questions

  • Why is counting better than sorting here?
  • How would you handle Unicode correctly?
  • How do you group many words into anagram sets efficiently?
  • Why is comparing character-code sums unreliable?

More Strings interview questions

View all →