Run your code 2 more times to open the solutions. The idea sticks better after an attempt. Valid Anagram in Python
2 reference approaches in Python, from brute force to the one to reach for. Compare them with yours.
Two anagrams hold the same letters, so putting each string's letters in order makes them identical. sorted() takes any string and returns a list of its characters in order, and comparing two lists checks every position. It is short and hard to get wrong, but sorting costs O(n log n) time and builds two new lists of n characters each, so it uses O(n) extra memory as well.
def is_anagram(s: str, t: str) -> bool:
return sorted(s) == sorted(t)
Order does not matter for an anagram, only how many times each letter appears. Count the letters of s up in one dictionary, then count the letters of t back down. Because the lengths already match, any extra letter in t must push some count below zero, and you can stop right there. Each character is touched once, and the dictionary never holds more than 26 keys. The standard library version is Counter(s) == Counter(t) from collections, which gives the same answers in the same O(n) time.
def is_anagram(s: str, t: str) -> bool:
if len(s) != len(t):
return False
counts: dict[str, int] = {}
for ch in s:
counts[ch] = counts.get(ch, 0) + 1
for ch in t:
counts[ch] = counts.get(ch, 0) - 1
if counts[ch] < 0: # t uses ch more often than s
return False
return True
Valid Anagram in JavaScript
2 reference approaches in JavaScript, from brute force to the one to reach for. Compare them with yours.
If two strings are rearrangements of each other, putting their characters in a fixed order turns them into the same string. Spreading with [...str] gives an array of characters, sort() without a comparator orders them by UTF-16 code unit (exactly what you want for letters, unlike for numbers), and join('') rebuilds a string that === can compare in one step. Two empty strings sort to '' and compare equal, which covers that case for free. The price is the sort, O(n log n), plus a temporary array and a joined string per input, so memory grows with the length too.
function isAnagram(s, t) {
const sortChars = (str) => [...str].sort().join('');
return sortChars(s) === sortChars(t);
}
An anagram only cares about how often each letter occurs. After the length test, walk s and bump a tally per character in a Map, then walk t and take one off. counts.get(ch) ?? 0 turns a letter s never had into a zero, so it drops straight to -1. With equal lengths, a surplus anywhere in t must drive some tally negative, so that is the only check the second loop needs. Every character is visited once, and the Map holds at most 26 entries however long the strings get.
function isAnagram(s, t) {
if (s.length !== t.length) return false;
const counts = new Map();
for (const ch of s) counts.set(ch, (counts.get(ch) ?? 0) + 1);
for (const ch of t) {
const left = (counts.get(ch) ?? 0) - 1;
if (left < 0) return false; // t uses ch more often than s
counts.set(ch, left);
}
return true;
}
Valid Anagram in TypeScript
2 reference approaches in TypeScript, from brute force to the one to reach for. Compare them with yours.
Sorting the characters of two anagrams gives the same sequence. [...s] turns the string into a string[], sort() with no comparator orders single letters by code unit, and join('') rebuilds a string that === compares in one step. The length test up front skips both sorts when the answer is already false. Time is O(n log n), and each input costs a temporary array and a joined string.
function isAnagram(s: string, t: string): boolean {
if (s.length !== t.length) return false;
const sorted = (str: string): string => [...str].sort().join('');
return sorted(s) === sorted(t);
}
Only how often each letter occurs matters. An Int32Array(26) starts at zero, and charCodeAt(i) - 97 maps a to 0 and z to 25. Count s up, then count t down: with equal lengths, a letter t uses too often must push its slot below zero, so that is the only check the second loop needs. One pass per string, and the array stays 26 integers however long the input gets.
function isAnagram(s: string, t: string): boolean {
if (s.length !== t.length) return false;
const counts = new Int32Array(26);
for (let i = 0; i < s.length; i++) counts[s.charCodeAt(i) - 97]++;
for (let i = 0; i < t.length; i++) {
const c = t.charCodeAt(i) - 97;
if (--counts[c] < 0) return false; // t uses this letter more often than s
}
return true;
}
Valid Anagram in Java
2 reference approaches in Java, from brute force to the one to reach for. Compare them with yours.
Once sorted, the characters of two anagrams line up as identical sequences. Because a String is immutable, toCharArray() returns a brand-new char[] that you are free to reorder. Arrays.sort on a primitive array sorts it in place with no wrapper objects, and the two-argument Arrays.equals compares lengths first, then element by element, so "cat" against "cart" fails on the length test. Mind which comparison you write: a == b and a.equals(b) both ask whether two variables point at one array, so either would answer false every time. Sorting puts the time at O(n log n), and the two copies cost O(n) memory.
import java.util.*;
public class Main {
static boolean isAnagram(String s, String t) {
char[] a = s.toCharArray();
char[] b = t.toCharArray();
Arrays.sort(a);
Arrays.sort(b);
return Arrays.equals(a, b);
}
}
Only the number of each letter decides the answer. new int[26] gives an array whose entries all start at 0, and s.charAt(i) - 'a' turns a letter into its index: subtracting two char values promotes both to int, so the result is 0 for a and 25 for z. One loop increments for s and a second decrements for t. The opening length comparison means a surplus letter in t has to drive its entry negative, so the method can return false on the spot. Each char is read once and the array stays 26 ints whatever the input length. Swapping in a HashMap<Character, Integer> yields identical results, but every update hashes the key and goes through boxed Character and Integer objects, which the primitive array avoids.
import java.util.*;
public class Main {
static boolean isAnagram(String s, String t) {
if (s.length() != t.length()) {
return false;
}
int[] counts = new int[26];
for (int i = 0; i < s.length(); i++) {
counts[s.charAt(i) - 'a']++;
}
for (int i = 0; i < t.length(); i++) {
int c = t.charAt(i) - 'a';
counts[c]--;
if (counts[c] < 0) { // t uses this letter more often than s
return false;
}
}
return true;
}
}
Valid Anagram in Go
2 reference approaches in Go, from brute force to the one to reach for. Compare them with yours.
Arrange the letters of two anagrams in order and you get one and the same sequence. A Go string cannot be modified, so []byte(s) first makes a copy that can be. slices.Sort orders each copy in place, and slices.Equal does the comparison, because Go will not accept two slices on either side of ==: a slice can only be compared with nil. For "cat" against "cart", slices.Equal sees a 3-byte slice and a 4-byte slice and says no before looking at a single element. Four lines of body is the appeal; the price is two sorts at O(n log n) and two conversions that each allocate a fresh n-byte slice, so the extra memory is O(n).
package main
import "slices"
func isAnagram(s string, t string) bool {
a, b := []byte(s), []byte(t)
slices.Sort(a)
slices.Sort(b)
return slices.Equal(a, b)
}
Where the letters sit is irrelevant; the tallies are all that decide it. Indexing a Go string with s[i] yields a byte, and subtracting 'a' maps it to slot 0 to 25 of var counts [26]int, which Go has already zeroed. The loops use for i := range len(s) to walk byte positions; ranging over the string itself would hand back runes instead. The first loop adds for s, the second subtracts for t, and since the opening len test guarantees equal lengths, a letter that t has too many of drives its slot negative and ends the call. Every byte is visited once, and the counter is 26 ints however large the input grows. A map[byte]int would give the same answers but pay for a hash lookup on every byte, which the array index skips.
package main
func isAnagram(s string, t string) bool {
if len(s) != len(t) {
return false
}
var counts [26]int
for i := range len(s) {
counts[s[i]-'a']++
}
for i := range len(t) {
c := t[i] - 'a'
counts[c]--
if counts[c] < 0 { // t uses this letter more often than s
return false
}
}
return true
}
Valid Anagram in C#
2 reference approaches in C#, from brute force to the one to reach for. Compare them with yours.
Sorted, the letters of two anagrams form the same sequence. A C# string is immutable, so ToCharArray() hands back a fresh char[] that Array.Sort can reorder in place with no allocations beyond the copy. The comparison needs care: a == b on two arrays is reference equality and would answer false every time, and the arrays have no value-based Equals. LINQ's SequenceEqual walks both arrays element by element and stops at the first mismatch; a length check up front skips the sort for "cat" against "cart". The sort sets the time at O(n log n) and the two copies cost O(n) memory.
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution
{
public static bool IsAnagram(string s, string t)
{
if (s.Length != t.Length) return false;
char[] a = s.ToCharArray();
char[] b = t.ToCharArray();
Array.Sort(a);
Array.Sort(b);
return a.SequenceEqual(b);
}
}
Only how often each letter appears matters. new int[26] starts every tally at zero, and c - 'a' maps a letter to its slot: subtracting two char values promotes both to int, giving 0 for a and 25 for z. A foreach over s counts up and a second over t counts down. Because the lengths were compared first, any letter t uses more often than s must push its tally below zero, so the method can return false at that moment with no final sweep. Each character is read once and the array stays 26 ints however long the input. A Dictionary<char, int> gives the same answers, but each update hashes the key and does a lookup, which the plain array avoids.
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution
{
public static bool IsAnagram(string s, string t)
{
if (s.Length != t.Length) return false;
int[] counts = new int[26];
foreach (char c in s)
{
counts[c - 'a']++;
}
foreach (char c in t)
{
int i = c - 'a';
counts[i]--;
if (counts[i] < 0) return false; // t uses this letter more often than s
}
return true;
}
}
Valid Anagram in C++
2 reference approaches in C++, from brute force to the one to reach for. Compare them with yours.
Sort both strings and compare them. The method takes s and t by value, so it already owns copies and sort(s.begin(), s.end()) can reorder them in place without touching the caller's strings. == on two std::strings checks the length first and then every character. Time is O(n log n) for the sorts, and the copies cost O(n) memory.
#include <algorithm>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.size() != t.size()) return false;
sort(s.begin(), s.end());
sort(t.begin(), t.end());
return s == t;
}
};
Only letter frequencies matter. int counts[26] = {} zero-initialises the tallies, and c - 'a' maps a letter to its slot. Count s up and t down; once the lengths match, a letter that t uses too often has to drive its slot below zero, so the method can return false right there. One pass per string and a fixed 26 ints of memory.
#include <algorithm>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
class Solution {
public:
bool isAnagram(string s, string t) {
if (s.size() != t.size()) return false;
int counts[26] = {};
for (char c : s) counts[c - 'a']++;
for (char c : t) {
if (--counts[c - 'a'] < 0) return false; // t uses c more often than s
}
return true;
}
};
Valid Anagram in C
2 reference approaches in C, from brute force to the one to reach for. Compare them with yours.
Copy each string into a malloc'ed buffer, sort the copies with qsort and compare them with memcmp. The copies matter: the input strings belong to the caller, so the function must not reorder them. strlen runs once per string and doubles as the length check. Time is O(n log n) for the sorts plus O(n) for the copies, which are freed before returning.
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
static int compareChars(const void* a, const void* b) {
return *(const unsigned char*)a - *(const unsigned char*)b;
}
bool isAnagram(char* s, char* t) {
size_t n = strlen(s);
if (n != strlen(t)) return false;
if (n == 0) return true;
char* a = malloc(n);
char* b = malloc(n);
memcpy(a, s, n);
memcpy(b, t, n);
qsort(a, n, 1, compareChars);
qsort(b, n, 1, compareChars);
bool same = memcmp(a, b, n) == 0;
free(a);
free(b);
return same;
}
Only letter frequencies matter, so 26 counters on the stack are enough. int counts[26] = {0} zeroes them, and c - 'a' picks the slot. One loop over both strings adds for s and subtracts for t; after equal lengths, every slot must be back at zero. Nothing is allocated, and each character is read once.
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
bool isAnagram(char* s, char* t) {
size_t n = strlen(s);
if (n != strlen(t)) return false;
int counts[26] = {0};
for (size_t i = 0; i < n; i++) {
counts[s[i] - 'a']++;
counts[t[i] - 'a']--;
}
for (int c = 0; c < 26; c++) {
if (counts[c] != 0) return false;
}
return true;
}
Valid Anagram in Kotlin
2 reference approaches in Kotlin, from brute force to the one to reach for. Compare them with yours.
Sorted, two anagrams become the same sequence of letters. toCharArray() copies each string into a primitive CharArray, apply sorts the copy in place with sort() and hands it back, and contentEquals compares the two arrays element by element (it also returns false when the sizes differ). Sorting costs O(n log n) time and the two copies O(n) memory.
class Solution {
fun isAnagram(s: String, t: String): Boolean {
if (s.length != t.length) return false
val a = s.toCharArray().apply { sort() }
val b = t.toCharArray().apply { sort() }
return a contentEquals b
}
}
Only how often each letter appears matters. IntArray(26) starts every count at 0, and c - 'a' turns a Char into its slot, because subtracting two Chars gives an Int in Kotlin. Count the letters of s up and the letters of t back down; with the lengths equal, a count dropping below zero is the only way to fail, so the method returns false right there. One pass over each string, 26 ints of memory.
class Solution {
fun isAnagram(s: String, t: String): Boolean {
if (s.length != t.length) return false
val counts = IntArray(26)
for (c in s) counts[c - 'a']++
for (c in t) {
if (--counts[c - 'a'] < 0) return false // t uses c more often than s
}
return true
}
}
Valid Anagram in Rust
2 reference approaches in Rust, from brute force to the one to reach for. Compare them with yours.
Sorted, two anagrams become the same bytes. The method owns both Strings, so into_bytes() turns each into a Vec<u8> without copying, and sort_unstable() sorts it in place with no extra allocation. Comparing two vectors with == checks the lengths and then every element. O(n log n) time, and the only memory is the buffers the strings already had.
impl Solution {
pub fn is_anagram(s: String, t: String) -> bool {
let mut a = s.into_bytes();
let mut b = t.into_bytes();
a.sort_unstable();
b.sort_unstable();
a == b
}
}
Only the number of each letter matters. A [i32; 26] array lives on the stack, and (b - b'a') as usize turns a byte into its slot. Count the bytes of s up and the bytes of t back down; with the lengths equal, a count going negative is the only way to fail, so the method returns false at once. One pass over each string and a fixed 26 counters.
impl Solution {
pub fn is_anagram(s: String, t: String) -> bool {
if s.len() != t.len() {
return false;
}
let mut counts = [0i32; 26];
for b in s.bytes() {
counts[(b - b'a') as usize] += 1;
}
for b in t.bytes() {
let c = &mut counts[(b - b'a') as usize];
*c -= 1;
if *c < 0 {
return false; // t uses this letter more often than s
}
}
true
}
}
Valid Anagram in Swift
2 reference approaches in Swift, from brute force to the one to reach for. Compare them with yours.
Sorted, two anagrams become the same sequence. A String is a collection of Characters, so s.sorted() returns a [Character] in order, and == on two arrays compares their counts and then every element. No Foundation is needed. O(n log n) time and two new arrays of O(n) memory.
class Solution {
func isAnagram(_ s: String, _ t: String) -> Bool {
return s.sorted() == t.sorted()
}
}
Only the number of each letter matters. s.utf8 walks the string as UInt8 bytes with no grapheme work, and Int(b - a) with a = UInt8(ascii: "a") picks one of 26 slots in an [Int]. Count the bytes of s up and those of t back down; once the lengths match, a count below zero is the only way to fail, so the method returns false there. One pass over each string and 26 counters.
class Solution {
func isAnagram(_ s: String, _ t: String) -> Bool {
if s.utf8.count != t.utf8.count { return false }
let a = UInt8(ascii: "a")
var counts = [Int](repeating: 0, count: 26)
for b in s.utf8 { counts[Int(b - a)] += 1 }
for b in t.utf8 {
counts[Int(b - a)] -= 1
if counts[Int(b - a)] < 0 { return false } // t uses this letter more often than s
}
return true
}
}
Valid Anagram in PHP
2 reference approaches in PHP, from brute force to the one to reach for. Compare them with yours.
Sorted, two anagrams become the same list of letters. str_split breaks each string into an array of one-character strings, sort orders that array in place (it takes it by reference and returns true, not the array), and === checks that both arrays hold the same values at the same keys. O(n log n) time and two arrays of O(n) memory.
<?php
class Solution {
/**
* @param string $s
* @param string $t
* @return bool
*/
function isAnagram(string $s, string $t): bool {
if (strlen($s) !== strlen($t)) {
return false;
}
$a = str_split($s);
$b = str_split($t);
sort($a);
sort($b);
return $a === $b;
}
}
Only the number of each letter matters. array_fill(0, 26, 0) makes 26 counters, ord($s[$i]) - 97 turns a letter into its slot, and the string offset $s[$i] reads one byte without splitting the string. Count $s up and $t back down; with the lengths equal, a counter below zero is the only way to fail, so the method returns false there. The built-in count_chars($s, 1) builds the same tally in C, keyed by byte value.
<?php
class Solution {
/**
* @param string $s
* @param string $t
* @return bool
*/
function isAnagram(string $s, string $t): bool {
$n = strlen($s);
if ($n !== strlen($t)) {
return false;
}
$counts = array_fill(0, 26, 0);
for ($i = 0; $i < $n; $i++) {
$counts[ord($s[$i]) - 97]++;
}
for ($i = 0; $i < $n; $i++) {
$c = ord($t[$i]) - 97;
if (--$counts[$c] < 0) {
return false; // $t uses this letter more often than $s
}
}
return true;
}
}
Valid Anagram in Ruby
2 reference approaches in Ruby, from brute force to the one to reach for. Compare them with yours.
Sorted, two anagrams become the same list of letters. s.chars splits a string into an Array of one-character strings, sort returns a sorted copy, and == on two arrays compares their sizes and then every element. O(n log n) time and O(n) memory for the arrays.
# @param {String} s
# @param {String} t
# @return {Boolean}
def is_anagram(s, t)
s.chars.sort == t.chars.sort
end
Only the number of each letter matters. Array.new(26, 0) makes 26 counters, and each_byte yields every letter as an Integer, so b - 97 is its slot with no string allocated per character. Count s up and t back down; with the lengths equal, a counter below zero is the only way to fail, and return false inside the block leaves the method at once. s.chars.tally == t.chars.tally is the one-line version, without the early exit.
# @param {String} s
# @param {String} t
# @return {Boolean}
def is_anagram(s, t)
return false unless s.length == t.length
counts = Array.new(26, 0)
s.each_byte { |b| counts[b - 97] += 1 }
t.each_byte do |b|
counts[b - 97] -= 1
return false if counts[b - 97].negative? # t uses this letter more often than s
end
true
end
Valid Anagram in Dart
2 reference approaches in Dart, from brute force to the one to reach for. Compare them with yours.
Sorted, two anagrams become the same string. codeUnits is a read-only view, so toList() copies it into a growable List<int>, and the cascade ..sort() sorts that copy and hands the list back. Dart's == on two lists only checks identity, so String.fromCharCodes turns each sorted list back into a String, which compares by value. O(n log n) time and O(n) memory.
class Solution {
bool isAnagram(String s, String t) {
if (s.length != t.length) return false;
final a = s.codeUnits.toList()..sort();
final b = t.codeUnits.toList()..sort();
return String.fromCharCodes(a) == String.fromCharCodes(b);
}
}
Only the number of each letter matters. List<int>.filled(26, 0) makes 26 counters, and s.codeUnitAt(i) - a (with a = 'a'.codeUnitAt(0)) is a letter's slot, read as an int without creating a one-character string. Count s up and t back down; with the lengths equal, a counter below zero is the only way to fail, so the method returns false there. One pass over each string and 26 counters.
class Solution {
bool isAnagram(String s, String t) {
if (s.length != t.length) return false;
final a = 'a'.codeUnitAt(0);
final counts = List<int>.filled(26, 0);
for (var i = 0; i < s.length; i++) {
counts[s.codeUnitAt(i) - a]++;
}
for (var i = 0; i < t.length; i++) {
final c = t.codeUnitAt(i) - a;
if (--counts[c] < 0) return false; // t uses this letter more often than s
}
return true;
}
}
Valid Anagram in Scala
2 reference approaches in Scala, from brute force to the one to reach for. Compare them with yours.
Sorted, two anagrams become the same string. On a String, sorted comes from StringOps and returns a new String with its characters in order, and == in Scala compares strings by value. The length check skips the sort for pairs that can never match. O(n log n) time and O(n) memory for the sorted copies.
object Solution {
def isAnagram(s: String, t: String): Boolean =
s.length == t.length && s.sorted == t.sorted
}
Only the number of each letter matters. new Array[Int](26) starts every counter at 0, and c - 'a' is an Int slot because Char arithmetic widens to Int. Count s up and t back down; with the lengths equal, a counter below zero is the only way to fail. The for body is a closure, so the method body is a boundary and break(false) leaves the loop with the answer.
import scala.util.boundary, boundary.break
object Solution {
def isAnagram(s: String, t: String): Boolean = boundary {
if (s.length != t.length) break(false)
val counts = new Array[Int](26)
for (c <- s) counts(c - 'a') += 1
for (c <- t) {
counts(c - 'a') -= 1
if (counts(c - 'a') < 0) break(false) // t uses this letter more often than s
}
true
}
}
FAQ for Python
Can I use a list of 26 counts instead of a dictionary?
Yes, when the input is only a to z. Make counts = [0] * 26, add 1 at ord(a) - ord("a") for each letter of s and subtract 1 for each letter of t, then return not any(counts). It gives True for "dusty" and "study" and False for "tool" and "lott", but any other character lands in the wrong slot or raises IndexError.
How do I check anagrams ignoring case or with Unicode letters?
Normalise both strings with str.casefold() first, then use the dictionary or Counter version, which works for any characters (the space is O(k) for k distinct characters). casefold is stronger than lower: "Straße".casefold() is "strasse". For example sorted("Tea".casefold()) == sorted("EAT".casefold()) is True.
How do I ignore spaces when checking phrase anagrams?
Remove the spaces before comparing, for example s.replace(" ", ""), or keep only letters with "".join(ch for ch in s if ch.isalpha()). Then "dormitory" and "dirty room" compare as True. Without that step the space alone makes the lengths differ.
Why check the lengths first?
Strings of different lengths can never be anagrams, and len is O(1), so it is a free early exit. In the counting version it also makes the early return correct: with equal lengths, every missing letter in t is matched by an extra one, so checking for a count below zero is enough and no final pass over the dictionary is needed.
FAQ for JavaScript
Can I count with a plain object instead of a Map?
Yes, but guard every read. A letter that s never contained reads as undefined, undefined - 1 is NaN, and NaN < 0 is false, so the negative check silently passes. A version that writes counts[ch]-- without a default returns true for 'ab' and 'ac'. Use (counts[ch] ?? 0) - 1 as the Map version does, or keep the Map.
Is a fixed array of 26 counters faster than a Map?
For strictly a to z input it avoids hashing. Create new Array(26).fill(0), add 1 at s.charCodeAt(i) - 97 and subtract 1 at t.charCodeAt(i) - 97 in the same loop, then return counts.every((c) => c === 0). That prints true for 'dusty'/'study' and false for 'tool'/'lott'. Any other character lands on a wrong or negative index, so keep the Map when input is not guaranteed.
How do I compare phrases with capitals and spaces?
Clean both sides first, for example x.toLowerCase().replace(/[^a-z]/g, ''), then run either check. Cleaned, 'Dormitory' and 'dirty room' give true; compared raw they give false, because the capital D and the space each count as characters.
Why spread the string instead of calling split with an empty string?
split('') cuts by UTF-16 code unit, so an emoji such as '😀' becomes two halves ('😀'.split('').length is 2, while [...'😀'].length is 1). Sorting the halves can make different emoji pairs look equal: '\u{1F600}\u{1F301}' and '\u{1F701}\u{1F200}' compare true after split('') and false after spreading. for...of in the Map version also walks whole code points.
Why does café fail against the same letters typed differently?
An accented letter can be one code point ('\u00e9') or a plain e followed by a combining accent ('e\u0301'). 'caf\u00e9' has length 4 and 'e\u0301fac' has length 5, so both checks say false. Call normalize('NFC') on each string first and the sort comparison returns true.
FAQ for TypeScript
Why an Int32Array instead of a Map<string, number>?
With input limited to a to z a fixed array of 26 slots needs no hashing and no ?? 0 defaults, because a typed array is zero-filled on creation. A Map<string, number> is the safer choice when the characters are not known in advance, since any key works.
What does TypeScript catch in this problem?
Mostly mix-ups between strings and numbers: counts[s[i]] on an Int32Array is a compile error because s[i] is a string, so you have to write s.charCodeAt(i) - 97. With noUncheckedIndexedAccess on, counts[c] is typed number | undefined and needs a guard; this lane checks non-strict, so the code above compiles as written.
Why does sort() work here when it breaks on numbers?
Without a comparator, sort() compares elements as strings by UTF-16 code unit. That is wrong for numbers ([10, 9].sort() gives [10, 9]), but for single letters it is exactly alphabetical order, so [...'study'].sort().join('') is 'dstuy', the same as for 'dusty'.
Should I spread the string or call split with an empty string?
For a to z both give the same array. Spreading walks code points, so an emoji stays one element, while split('') cuts it into two surrogate halves that the sort can then mix with other emoji. Prefer [...str] when the input might contain characters outside the Basic Multilingual Plane.
How do I compare phrases that have capitals and spaces?
Clean both strings first, for example const clean = (x: string) => x.toLowerCase().replace(/[^a-z]/g, ''), then run either check. Cleaned, 'Dormitory' and 'dirty room' are anagrams; raw, the capital and the space make them differ.
FAQ for Java
Why does comparing the sorted arrays with == give false?
Arrays in Java do not override equals, so a == b and a.equals(b) both test whether the two references point at the same object. toCharArray() creates a new array on every call, so either comparison would say false even for "dusty" and "study". Arrays.equals(a, b) is the content check; for arrays of arrays the matching call is Arrays.deepEquals.
Can sorting a char array give a wrong answer for emoji?
Yes. A char is one UTF-16 code unit, so anything above U+FFFF, most emoji included, takes two of them: a high and a low surrogate. toCharArray() exposes those halves and the sort moves them independently. "🔥🤔" (U+1F525, U+1F914) and "🔔🤥" (U+1F514, U+1F925) each have a length() of 4 and contain the same four surrogates, so the char version says true for two strings with no emoji in common. Sorting code points fixes it: Arrays.equals(s.codePoints().sorted().toArray(), t.codePoints().sorted().toArray()) says false for that pair and true for "niño" and "oñin". Letters such as é and ш fit in a single char, so they are not affected.
What replaces the int[26] when the input is not just a to z?
A HashMap<Integer, Integer> keyed by code point. Build it with s.codePoints().forEach(cp -> counts.merge(cp, 1, Integer::sum)), then walk t.codePoints(), merge -1 for each, and return false once a value goes negative. That gives false for "🔥🤔" against "🔔🤥" and true for "niño" against "oñin", using O(k) space for k distinct code points, with every key and count boxed. Feeding uppercase to the array version breaks it: char arithmetic happens in int, so for "Tea" the index 'T' - 'a' is -13 and the call throws ArrayIndexOutOfBoundsException: Index -13 out of bounds for length 26.
How do I ignore upper and lower case safely?
Call toLowerCase(Locale.ROOT) on both strings before counting: the code point version says false for "Tea" and "EAT" as given and true once both are lowered. Spell out the locale, because the no-argument toLowerCase() follows the default locale, and under Turkish rules "TITLE".toLowerCase() yields "tıtle" with a dotless ı. Uppercasing uses full case mapping, so "Straße".toUpperCase(Locale.ROOT) is "STRASSE", yet lowercasing leaves "straße" and "Straße".equalsIgnoreCase("STRASSE") is false. To make ß equal ss, uppercase both sides instead.
How do I compare phrases such as dormitory and dirty room?
Drop the whitespace first. s.replace(" ", "") handles ordinary spaces with no regex involved; s.replaceAll("\\s+", "") also strips tabs and line breaks, but compiles a regular expression on every call. Once stripped, "dormitory" and "dirty room" give true. Skip the step and the extra space makes length() differ, so the method returns false straight away.
FAQ for Go
Why use slices.Equal instead of == on the sorted slices?
Because slices are not comparable in Go: a == b with two []byte operands does not compile, since a slice may only be compared with nil. slices.Equal (or bytes.Equal for byte slices) checks the lengths and then each element. Arrays are another matter: [26]int is comparable, so a variant of the counting version could fill one array from s, a second from t, and return ca == cb. That works, but it always reads both strings to the end instead of stopping at the first negative slot.
Is the byte sort safe for strings with accents or Cyrillic?
No. A multi-byte UTF-8 character becomes several elements of []byte(s), and the sort mixes bytes that belong to different characters. "éш" is stored as [195 169 209 136] and "Èѩ" as [195 136 209 169]; after sorting both are the same four bytes, so the function reports true for two strings with no character in common. Convert with []rune(s) instead, one element per code point, and sort those: the pair now comes out false, while "niño" and "oñin" still come out true.
How do I handle input beyond lowercase a to z?
Range over the string rather than indexing it: for _, r := range s decodes UTF-8 and yields one rune per character. Tally into a map[rune]int; a missing key reads as the zero value, so counts[r]++ needs no comma-ok check. Subtract while ranging over t and return false once a count goes negative. That answers false for "éш" versus "Èѩ" and true for "niño" versus "oñin", in O(k) space for k distinct runes. The [26]int version fails loudly on other input: s[i] is a byte, so for "Tea" the expression 'T' - 'a' wraps to 243 and the program panics with index out of range [243] with length 26.
How do I make the check case-insensitive?
Pass both strings through strings.ToLower before tallying runes. "Tea" and "EAT" then come out true; untouched they are false. Go maps case rune for rune, so strings.ToLower("Straße") stays "straße" and strings.EqualFold("Straße", "STRASSE") is false. If ß has to match ss, reach for full case folding in golang.org/x/text/cases, a module outside the standard library.
What about multi-word anagrams with spaces?
Strip the spaces first. strings.ReplaceAll(s, " ", "") removes plain spaces; strings.Join(strings.Fields(s), "") also removes tabs and newlines, because Fields splits on any whitespace. After that "dormitory" and "dirty room" give true. Leave the space in and the byte lengths differ by one, so the early len test returns false.
FAQ for C#
Why does comparing the sorted char arrays with == return false?
Arrays are reference types and do not overload == or override Equals, so a == b and a.Equals(b) both ask whether the two variables point at the same array. ToCharArray() allocates a new one on every call, so either check says false even for "dusty" and "study". Use a.SequenceEqual(b) from System.Linq, or build strings and compare those: new string(a) == new string(b) is value equality because string overloads ==.
Can I just use string.Concat(s.OrderBy(c => c)) and compare the strings?
Yes, and it is the shortest version: string.Concat(s.OrderBy(c => c)) == string.Concat(t.OrderBy(c => c)). It is still O(n log n), but OrderBy materialises a buffer and uses a stable sort with key extraction, and Concat builds two more strings, so it allocates several times more than ToCharArray plus Array.Sort. Fine for short words; for the size bound here the array version is noticeably lighter.
What happens if the input has uppercase letters or characters outside a to z?
The int[26] version computes c - 'a', and for 'T' that is -13, so the indexer throws IndexOutOfRangeException. For arbitrary characters use a Dictionary<char, int>: CollectionsMarshal.GetValueRefOrAddDefault from System.Runtime.InteropServices increments in one lookup, or plainly counts[c] = counts.GetValueOrDefault(c) + 1. Space becomes O(k) for k distinct characters. Also note a char is one UTF-16 code unit, so emoji take two and sort as separate halves; s.EnumerateRunes() gives you whole code points when that matters.
How do I ignore case safely?
Lowercase both strings with ToLowerInvariant() before counting, then "Tea" and "EAT" compare as anagrams. Prefer the invariant form over ToLower(): ToLower() follows the current culture, and under a Turkish culture "TITLE".ToLower() produces a dotless ı. string.Equals(a, b, StringComparison.OrdinalIgnoreCase) is the right tool for a plain comparison, but it does not help here because the letters must be counted, not compared in place.
How do I compare phrases such as dormitory and dirty room?
Strip the whitespace first. s.Replace(" ", "") removes ordinary spaces with no regex; string.Concat(s.Where(c => !char.IsWhiteSpace(c))) also drops tabs and line breaks. Once stripped, "dormitory" and "dirty room" give true. Skip the step and the extra space alone makes the lengths differ, so the method returns false at the first line.
FAQ for C++
Does sorting s and t change the strings the caller passed?
No. The parameters are string by value, so the function works on its own copies. If the signature took const string& you would have to copy first (string a = s;) before calling sort, because a const reference cannot be reordered.
Why int counts[26] = {} and not just int counts[26]?
A local array without an initialiser holds whatever was on the stack, so the tallies would start at garbage. The empty braces value-initialise all 26 entries to 0. std::array<int, 26> counts{} does the same with a bounds-checked at() if you want one.
Can I use unordered_map<char, int> instead of the array?
Yes, and it handles any byte, not just a to z. It is slower for this input because every update hashes the key and may allocate a node, while the array is a single indexed add. counts[c]++ on the map inserts a zero for a new key first, which is what you want here.
What happens with uppercase letters or other characters?
'T' - 'a' is negative, so counts[c - 'a'] writes outside the array, which is undefined behaviour. Normalise first with tolower from <cctype> (cast to unsigned char before calling it) or switch to int counts[256] indexed by (unsigned char)c.
Is there a one-line standard library check?
is_permutation(s.begin(), s.end(), t.begin(), t.end()) from <algorithm> answers exactly this question, but its worst case is O(n²) comparisons, so on 20,000 letters it is far slower than sorting or counting.
FAQ for C
Why not sort s and t in place?
The strings belong to the caller, and a check function that reorders its inputs is a nasty surprise; a string literal passed in would even be read-only memory, so writing to it can crash. Sorting malloc'ed copies keeps the inputs untouched, and the copies are freed before the function returns.
Why does the qsort comparator cast to unsigned char?
qsort hands the comparator const void* pointers, so it must cast them to the element type before reading. Using unsigned char keeps every byte in 0 to 255, so the subtraction cannot overflow and bytes above 127 sort after ASCII rather than as negative values on platforms where char is signed.
Is the result something the caller has to free?
No. The function returns a bool by value, so there is nothing to own. Only array and string results are malloc'ed and handed to the caller; here the only allocations are the sorting copies, and the function frees them itself.
Why call strlen only once per string?
A C string does not store its length; strlen walks to the NUL terminator every time. Writing for (i = 0; i < strlen(s); i++) rescans the string on every iteration and turns an O(n) loop into O(n²), which on 20,000 letters is hundreds of millions of reads.
What if the input is not just a to z?
s[i] - 'a' is then negative or above 25 and indexes outside the array, which is undefined behaviour. Use int counts[256] indexed by (unsigned char)s[i] to cover every byte, or normalise with tolower from <ctype.h> first. Multibyte UTF-8 letters still count byte by byte, which is fine for an exact-match check but not for case folding.
FAQ for Kotlin
Why contentEquals and not == for the sorted arrays?
Arrays on the JVM do not override equals, so a == b on two CharArrays checks whether they are the same object and is false for two separate copies, even for "dusty" and "study". The IDE flags it for that reason. a contentEquals b compares the elements; contentDeepEquals does the same for nested arrays.
Why does c - 'a' give an Int?
Kotlin defines Char - Char as an Int (the distance between the two code units), so 'c' - 'a' is 2 and can index the IntArray directly. Char + Int goes the other way and gives a Char. Arithmetic between a Char and an Int on the left, such as 1 + 'a', does not compile.
Why toCharArray().apply { sort() } instead of toCharArray().sorted()?
sort() sorts the primitive CharArray in place and returns Unit, so apply is used to get the array back. sorted() returns a new List<Char> of boxed characters; s.toList().sorted() == t.toList().sorted() passes too, because List equality compares the elements, but it allocates more.
Is there a one-line counting version?
s.groupingBy { it }.eachCount() == t.groupingBy { it }.eachCount() builds a Map<Char, Int> for each string, and two maps are equal when they hold the same entries. It works for any characters, not only a to z, at the cost of boxed keys and values and no early exit.
How do I ignore case and spaces?
Normalise both strings first: s.lowercase().filter { it.isLetter() }. Since Kotlin 1.5 lowercase() uses the invariant locale, so it does not turn I into a dotless ı on a Turkish machine the way Java's no-argument toLowerCase() can. After that, "Dormitory" and "dirty room" compare as anagrams.
FAQ for Rust
Why sort bytes and not chars?
The input is ASCII, where one byte is one letter, so sorting into_bytes() is correct and avoids decoding UTF-8. For general text, sort the code points instead: let mut a: Vec<char> = s.chars().collect(); a.sort_unstable();. Sorting the bytes of non-ASCII text can call two different strings anagrams, because the bytes of multi-byte characters get mixed.
Why sort_unstable instead of sort?
sort is a stable sort that allocates a scratch buffer. Stability means nothing for equal bytes, so sort_unstable, which sorts in place without allocating, is the faster choice. Both pass.
What happens with an uppercase letter in the counting version?
b'A' - b'a' is 65 - 97 in u8, which underflows. In a debug build that panics with "attempt to subtract with overflow"; in release it wraps to 224 and the index panics as out of bounds. For mixed input, lowercase first with to_ascii_lowercase() or count in a HashMap<char, i32>.
How do I count with a HashMap for any characters?
Use the entry API: *counts.entry(c).or_insert(0) += 1 for each c in s.chars(), then subtract for t.chars(). Two HashMaps also compare with == by content, so building one per string and comparing them works too, at O(k) space for k distinct characters.
Why let c = &mut counts[...] in the second loop?
It borrows the array element mutably once, so the decrement and the check use the same slot without computing the index twice. *c -= 1 writes through the reference. Writing counts[i] -= 1; if counts[i] < 0 is equivalent.
FAQ for Swift
Is s.count a cheap length check?
No. String.count counts Characters, which are extended grapheme clusters, so it walks the whole string in O(n). s.utf8.count is O(1) for a native Swift string, which is why the counting version compares the utf8 counts. For ASCII input the two numbers are the same.
Does s.sorted() handle accents and emoji?
Yes, because it sorts whole Characters: an emoji or a letter with a combining accent stays one element. Swift also compares Characters by canonical equivalence, so "e\u{301}" (e plus a combining accent) equals the single scalar "\u{E9}". The byte counting version only works for a to z; for other text count into a [Character: Int] dictionary.
Why count s.utf8 instead of looping over the Characters?
Iterating a String yields Characters and has to find each grapheme boundary, which is slow next to reading bytes. s.utf8 hands out raw UInt8 code units, and UInt8(ascii: "a") gives the byte 97 for the subtraction without any conversion.
What happens if the input has an uppercase letter?
UInt8(ascii: "A") - UInt8(ascii: "a") is 65 - 97 in UInt8, and Swift traps on unsigned underflow, so that case crashes with an arithmetic overflow. Lowercase both strings first with s.lowercased(), which is part of the standard library, or use the sorted() version.
Do I need import Foundation for this problem?
No. sorted(), lowercased(), utf8 and filter { $0.isLetter } are all in the standard library. Importing Foundation only adds start-up time to every Run here.
FAQ for PHP
Why not $a = sort(str_split($s))?
sort takes its array by reference, sorts it in place and returns true, so $a would be a boolean. Passing a function result straight to it also raises the notice "Only variables should be passed by reference". Store the array in a variable, call sort($a); on its own line, then compare.
Can count_chars do the whole check?
Yes: count_chars($s, 1) == count_chars($t, 1). Mode 1 returns an array from byte value to count, holding only the bytes that occur, and == on arrays is true when both hold the same key and value pairs. It is the shortest correct answer for byte strings and runs in O(n), without the early exit.
What about UTF-8 letters such as é?
strlen, str_split, $s[$i] and count_chars all work on bytes, and é is two bytes in UTF-8. Use the multibyte functions for real characters: mb_str_split($s) (PHP 7.4+) gives one element per character, and sorting those arrays compares characters, not byte fragments.
What does str_split return for an empty string?
Since PHP 8.2 it returns []; before that it returned [""], an array with one empty string. For two empty strings both versions give equal arrays, so the answer is true either way, but code that counts the elements of the result should not rely on the old behaviour.
Should I compare the sorted arrays with == or ===?
=== requires the same key and value pairs in the same order with the same types; == allows loose type juggling. After sort both arrays are lists of one-character strings, so both operators give the same answer, and === is the safer habit.
FAQ for Ruby
What does tally do here?
s.chars.tally (Ruby 2.7+) returns a Hash from each character to how often it occurs, so "tool".chars.tally maps "t" and "l" to 1 and "o" to 2. Two hashes are == when they hold the same pairs, whatever their insertion order, so s.chars.tally == t.chars.tally is a complete anagram check for any characters.
Why each_byte instead of each_char?
each_char yields a new one-character String for every letter, while each_byte yields plain Integers, which are cheaper and can index the array directly after subtracting 97 ("a".ord). For text beyond a to z, use each_char with Hash.new(0) as the counter.
Does return false inside the each_byte block stop the method?
Yes. A block is not its own method, so return in it returns from is_anagram and abandons the rest of the loop. break would only leave the block and carry on with the next line of the method.
Is s.bytes.sort faster than s.chars.sort?
Usually, because it sorts Integers instead of one-character Strings. For lowercase ASCII both give the same answer. For UTF-8 text keep chars: it splits by character, while bytes splits multi-byte characters into fragments.
How do I ignore case and spaces?
Normalise both strings first, for example s.downcase.delete(" "), or keep letters only with s.downcase.gsub(/[^a-z]/, ""). downcase handles Unicode letters since Ruby 2.4. Then "Dormitory" and "dirty room" compare as anagrams.
FAQ for Dart
Why does comparing the two sorted lists with == return false?
List does not override == in Dart, so [1, 2] == [1, 2] is false: it asks whether both sides are the same object. Compare the contents instead, by turning the lists back into strings with String.fromCharCodes, with a loop, or with ListEquality from package:collection where that package is available.
Why toList() before sort()?
s.codeUnits is an unmodifiable view of the string, so calling sort() on it throws Unsupported operation: Cannot modify an unmodifiable list. toList() makes a modifiable copy that can be sorted in place.
What does the ..sort() cascade do?
sort() returns void, so final a = list.sort(); would not compile. The cascade .. calls sort() on the list and then evaluates to the list itself, which lets the copy and the sort happen in one expression.
Why codeUnitAt(i) instead of s[i]?
s[i] returns a new one-character String, while codeUnitAt(i) returns the UTF-16 code unit as an int, which can index the counter list directly. For text with emoji, which take two code units, iterate s.runes to get whole code points and count them in a Map<int, int>.
How do I ignore case and spaces?
Normalise both strings first: s.toLowerCase().replaceAll(' ', ''), or keep letters only with replaceAll(RegExp(r'[^a-z]'), '') after lowercasing. Then "Dormitory" and "dirty room" compare as anagrams.
FAQ for Scala
Why does s.sorted == t.sorted work when Java needs Arrays.equals?
StringOps.sorted returns a String, not an array, and Scala's == calls equals, which compares strings by content. Sorting two Array[Char]s and comparing them with == would test identity, as in Java; for arrays use sameElements.
Why boundary and break instead of return false?
The body of for (c <- t) is a closure passed to foreach, so a return inside it is a non-local return, which Scala 3 deprecates with a warning. boundary { ... } with break(false) ends the loop and makes false the method result. A while loop with an index avoids the closure as well.
Why is c - 'a' an Int?
Arithmetic on Char widens both operands to Int, so 'c' - 'a' is 2 and indexes the array directly. Going back needs a conversion: ('a' + 2).toChar is 'c'.
Is there a one-line counting version?
s.groupMapReduce(identity)(_ => 1)(_ + _) == t.groupMapReduce(identity)(_ => 1)(_ + _) builds a Map[Char, Int] per string (Scala 2.13+), and two maps are equal when they hold the same entries. It works for any characters but boxes every key and count and has no early exit.
How do I ignore case and spaces?
Normalise both strings first: s.toLowerCase.filter(_.isLetter). Then "Dormitory" and "dirty room" compare as anagrams with either solution, as long as the counting one uses a Map for letters outside a to z.
Keep going
Valid Palindrome5 / 40 · Strings · EasyTry Valid Anagram in Python (Valid Anagram in Python), JavaScript (Valid Anagram in JavaScript), TypeScript (Valid Anagram in TypeScript), Go (Valid Anagram in Go), C# (Valid Anagram in C#), C++ (Valid Anagram in C++), C (Valid Anagram in C), Kotlin (Valid Anagram in Kotlin), Rust (Valid Anagram in Rust), Swift (Valid Anagram in Swift), PHP (Valid Anagram in PHP), Ruby (Valid Anagram in Ruby), Dart (Valid Anagram in Dart) or Scala (Valid Anagram in Scala) instead.