DSAPrep
EasyArrays & Hashing

Valid Anagram

Given two strings s and t, return true if t is an anagram of s, and false otherwise.

Example 1

Input: s = "anagram", t = "nagaram"
Output: true

Example 2

Input: s = "rat", t = "car"
Output: false

Constraints

  • 1 <= s.length, t.length <= 5 * 10^4
  • s and t consist of lowercase English letters.
Follow-up: What if the inputs contain Unicode characters? How would you adapt your solution to such a case?
View original on LeetCode ↗

Two strings are anagrams exactly when they contain the same letters the same number of times. That’s a statement about counts, not order, so the fastest way to check it avoids arranging the letters at all — it just tallies them.

Sort and Compare

Time O(n log n)Space O(n)

If s and t are anagrams, sorting both produces identical strings. If they aren’t, sorting won’t magically make them equal.

class Solution:
def isAnagram(self, s: str, t: str) -> bool:
return sorted(s) == sorted(t)

Correct and simple, but sorted() allocates new lists and costs O(n log n) — more work than the comparison actually requires, since it also implicitly checks length equality and character multiplicity together.

Character Counting

OptimalTime O(n)Space O(1)

Count every character in s into a hash map, then walk t decrementing those same counts. If a character in t isn’t in the map, or a count ever goes negative, they can’t be anagrams. If every count lands back at zero, they are.

class Solution:
def isAnagram(self, s: str, t: str) -> bool:
if len(s) != len(t):
return False
counts = {}
for ch in s:
counts[ch] = counts.get(ch, 0) + 1
for ch in t:
if ch not in counts:
return False
counts[ch] -= 1
if counts[ch] == 0:
del counts[ch]
return len(counts) == 0

Tracing s = "cat", t = "tac" — first the counting pass over s:

c
0
a
1
t
2

Hash Map

c1
1 / 6
resultcurrent

Count c in s. c now has count 1.

Correctness: the map after the first pass records exactly how many of each character s needs. The second pass spends those counts one by one; if t ever asks for a character that isn’t available, the strings aren’t anagrams. Since len(s) == len(t) is checked up front, ending with every count spent to zero proves the multisets match exactly.

Complexity: two linear passes over strings of length nO(n) time. With lowercase English letters the map holds at most 26 entries — O(1) space (for the Unicode follow-up, the map would instead hold up to n distinct code points, making space O(n) — the algorithm itself needs no other change since a hash map works for any hashable character set).