LC #242: Valid Anagrams

LilSardarXLilSardarX
3 min read

๐Ÿง  Problem Statement

Given two strings s and t, return true if t is an anagram of s, and false otherwise.
An anagram uses the same characters and the same frequency, but in any order.

Valid Anagram โ€“ LC #242


๐Ÿ’ฅ Brute Force

// generate all permutations of s and check if t exists in it
List<String> perms = generatePermutations(s);  
return perms.contains(t);
  • Time: O(n!) โ† factorial due to permutations
  • Space: O(n) or more
    โŒ Not scalable. Just a theoretical baseline.

โšก Optimized: Frequency Count using Array

int[] freqArr = new int[26];                         // fixed-size array for lowercase aโ€“z (O(1) space)

for (char c : s.toCharArray())                       // count frequency of each char in s
    freqArr[c - 'a']++;

for (char c : t.toCharArray()) {                     // decrement frequency for each char in t
    if (freqArr[c - 'a'] < 1) return false;          // char not present or used too many times
    freqArr[c - 'a']--;
}

for (int count : freqArr)                            // final check: all frequencies must be zero
    if (count != 0) return false;

return true;                                         // all matched โ€” valid anagram
  • Time: O(n) โ† traverse both strings once
  • Space: O(1) โ† uses 26-sized array for lowercase chars

โœ… Simple. Fast. Most interviewer-friendly.


๐Ÿง  Key Insights

  • Anagram = same characters + same frequencies (order doesn't matter)
  • Sorting approach works too (Arrays.sort) but is slower โ†’ O(n log n)
  • Better to count character frequencies โ†’ O(n)
  • Initially considered 2 HashMaps โ†’ works but not optimal
  • Use 1 array or 1 HashMap instead โ€” cleaner + space-efficient
  • If using array, final check = all values must be 0
  • โœ… For lowercase only:

    int[] freq = new int[26];  
    index = c - 'a';
    
  • โœ… For alphanumeric (Aโ€“Z, aโ€“z, 0โ€“9):
    Total possible chars = 62

    if (Character.isUpperCase(c)) index = c - 'A';           // 0โ€“25  
    else if (Character.isLowerCase(c)) index = c - 'a' + 26; // 26โ€“51  
    else index = c - '0' + 52;                               // 52โ€“61
    
  • ๐ŸŒ For arbitrary Unicode (e.g., emojis, symbols):
    Use HashMap<Character, Integer> for dynamic char support
    โ†ช You lose O(1) space, but gain generality


๐Ÿงช Dry Run + Test Cases

โœ… Test Case 1

Input: s = "aabb", t = "baba"

Steps:

  • Count s: a+2, b+2 โ†’ freq = [2a, 2b]
  • Use t: bโ€“1, aโ€“1, bโ€“1, aโ€“1 โ†’ all counts zero
    โœ… Final freq array = all zeros โ†’ return true

โœ… Test Case 2

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

Steps:

  • Count s: r+1, a+1, t+1
  • Use t: c not in freq โ†’ return false
    โŒ Extra char โ†’ not an anagram

โš ๏ธ Edge Case 1

Input: s = "", t = ""

Steps:

  • Both strings empty โ†’ no characters to mismatch
    โœ… return true (by definition)

โš ๏ธ Edge Case 2

Input: s = "a", t = ""

Steps:

  • Count s: a+1
  • t is empty โ†’ never decrements
    โŒ leftover a in freq โ†’ return false

๐Ÿ” Similar Problems

0
Subscribe to my newsletter

Read articles from LilSardarX directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

LilSardarX
LilSardarX

Iโ€™m figuring things out in tech โ€” and blogging along the way. I write what I learn, so I can revise it later and maybe help you avoid a few rabbit holes.