AlgoMaster Logo

Valid Anagram

easyFrequency6 min readUpdated June 23, 2026

Understanding the Problem

Two strings are anagrams if and only if they contain the exact same characters with the exact same frequencies. "listen" and "silent" are anagrams because both have one 'l', one 'i', one 's', one 't', one 'e', and one 'n'. "hello" and "world" are not, because their character counts differ.

The problem reduces to checking whether two strings have identical character frequency distributions. We can do this by sorting both strings, or by counting characters directly.

Key Constraints:

  • 1 <= s.length, t.length <= 5 * 10^4 → With n up to 50,000, an O(n^2) comparison would mean 2.5 billion operations, which is too slow. O(n log n) and O(n) both work.
  • s and t consist of lowercase English letters → Only 26 possible characters, so a fixed-size array of length 26 is enough to count frequencies. A hash map is needed only if the alphabet is unbounded (the Unicode follow-up).

Approach 1: Sorting

Intuition

Sort both strings and compare them. If the sorted versions are identical, the original strings contain the same characters in the same quantities, only in a different order. If they differ at any position, the strings hold different multisets of characters and cannot be anagrams.

Sorting normalizes order: it forces any anagram into the same canonical sequence. Two bags of Scrabble tiles arranged alphabetically produce identical rows if and only if the bags hold the same tiles.

Algorithm

  1. If s and t have different lengths, return false immediately.
  2. Sort both strings alphabetically.
  3. Compare the sorted strings character by character.
  4. If they match, return true. Otherwise, return false.

Example Walkthrough

Input:

0
a
1
n
2
a
3
g
4
r
5
a
6
m
s
0
n
1
a
2
g
3
a
4
r
5
a
6
m
t

After sorting both strings:

0
a
1
a
2
a
3
g
4
m
5
n
6
r
sorted(s)
0
a
1
a
2
a
3
g
4
m
5
n
6
r
sorted(t)

Both sorted strings are identical, so we return true.

Code

Sorting establishes a full ordering of every character, but the answer only depends on whether the frequencies match. Counting characters directly avoids the sort and brings the time down to linear.

Approach 2: Hash Map (Frequency Count)

Intuition

Count how often each character appears in both strings and compare the counts. Two strings are anagrams if and only if every character appears the same number of times in each.

The problem guarantees only lowercase English letters, so a fixed-size array of length 26 replaces the hash map. Indexing the array by char - 'a' gives constant-time access, and the space stays constant regardless of input length.

A single array handles both strings at once: increment the count for each character in s, decrement it for each character in t. After processing both strings, every count is the frequency in s minus the frequency in t. The strings are anagrams exactly when every entry returns to zero.

Algorithm

  1. If s and t have different lengths, return false.
  2. Create a frequency array of size 26 (one slot per letter).
  3. For each character in s, increment the corresponding count.
  4. For each character in t, decrement the corresponding count.
  5. If any count is not zero, return false. Otherwise, return true.

Example Walkthrough

s
1i=0: s[0]='a' → count['a']++, t[0]='n' → count['n']--
0
a
i
1
n
2
a
3
g
4
r
5
a
6
m
t
1i=0: t[0]='n' → count['n']--
0
n
i
1
a
2
g
3
a
4
r
5
a
6
m
count
1i=0: count['a']++ → 1, count['n']-- → -1
a
:
1
n
:
-1
1/6

Code

This approach is optimal in Big-O terms, but it depends on the alphabet being fixed at 26 lowercase letters. The follow-up asks what changes for Unicode input, where the character set is far larger and an array indexed by char - 'a' no longer applies.

Approach 3: Hash Map (Arbitrary Alphabet)

Intuition

The counting idea does not require a 26-slot array. Replacing the array with a hash map keyed by the character itself removes the assumption that input is lowercase ASCII, so the same frequency-difference logic works for Unicode, mixed case, digits, or any alphabet.

The map stores only the characters that appear, so its size is bounded by the number of distinct characters rather than a fixed 26. Everything else mirrors Approach 2: increment for s, decrement for t, and check that every stored count is zero.

Algorithm

  1. If s and t have different lengths, return false.
  2. Create an empty hash map from character to count.
  3. For each character in s, increment its count in the map.
  4. For each character in t, decrement its count in the map.
  5. If every value in the map is zero, return true. Otherwise, return false.

Example Walkthrough

Take s = "rat" and t = "car", which have equal length but are not anagrams. The first pass builds the counts for s, and the second pass subtracts the counts for t.

s
1Increment counts for each character in s = "rat"
0
r
1
a
2
t
t
1Waiting: count s first
0
c
1
a
2
r
map
1Counting s: r→1, a→1, t→1
r
:
1
a
:
1
t
:
1
1/5

After both passes, map['t'] is 1 and map['c'] is -1, so not every count is zero and the function returns false. For an anagram like "anagram" and "nagaram", every entry would cancel back to zero and the function would return true.

Code