Problem overview
The method IsAnagram receives two strings, s and t, and returns true when t can be formed by rearranging the letters of s, using every letter exactly once. Both strings hold lowercase letters, and each has between 1 and 50,000 of them.
"anagram" and "nagaram" are anagrams, so the result is true. "rat" and "car" are not: the letters differ, so the result is false.
Approach: sort both, then compare
Two words are anagrams when they contain the same letters with the same counts, and only the order differs. Sorting removes the order. If you sort the letters of both words, anagrams turn into identical strings, and non-anagrams don't.
For "anagram" and "nagaram", both sort to aaagmnr, so they match. For "rat" and "car" the sorted forms are art and acr, which differ.
The lesson asks for O(n log n) time and O(n) extra space for the sorted copies. Counting the letters instead of sorting them takes O(n) time and has its own lesson; sorting is the simplest to write and reason about.
Step by step
- Copy
sinto achar[]and sort it. A C#stringis immutable, so it can't be sorted in place.s.ToCharArray()returns a new array of its letters, andArray.Sort(sortedS)sorts that array in place, in ascending order. - Do the same for
t, intosortedT. Both strings get the same treatment, so equal letters end up at equal positions. - Compare the two arrays item by item with
sortedS.SequenceEqual(sortedT)and return the result. It istrueonly when both arrays have the same length and the same letter at every position.
The solution in C#
class Solution {
public bool IsAnagram(string s, string t) {
char[] sortedS = s.ToCharArray();
Array.Sort(sortedS);
char[] sortedT = t.ToCharArray();
Array.Sort(sortedT);
return sortedS.SequenceEqual(sortedT);
}
}
The C# details worth knowing:
- Why not
==on the arrays? For arrays,==asks whether both variables refer to the very same array object. Two separate arrays with identical letters givefalse.SequenceEqualcompares the contents instead. Strings are different:==on twostringvalues compares their characters. - Different lengths.
SequenceEqualreturnsfalsefor"ab"and"abb", since one array has an item more. That also handles the case where the strings have different lengths and so can't be anagrams. SequenceEqualis a LINQ method. It comes fromSystem.Linq, andArrayis inSystem, so a standalone file needsusing System;andusing System.Linq;at the top.Array.Sortreturns nothing. It reorders the array you give it and returnsvoid. Writingchar[] sortedS = Array.Sort(s.ToCharArray());doesn't compile.- The original strings are untouched. Sorting works on the copies. After the call,
sandtstill hold their original letters. - How letters sort.
charvalues sort by their numeric code, so'a'comes before'b'. For lowercase letters this is alphabetical order.
Complexity
Let n be the length of s and m the length of t.
Time: O(n log n + m log m). Sorting s costs O(n log n) and sorting t costs O(m log m). Copying the letters and comparing the two sorted arrays are both linear and don't change the total.
Space: O(n + m). The two char[] copies hold every letter of both strings.
Edge cases and common mistakes
- Different lengths.
"ab"and"abb"returnsfalse. A comparison that only looks at the letters of the shorter array would wrongly accept them. - Same letters, different counts.
"aab"and"abb"have the same length and the same set of letters but are not anagrams: their sorted forms areaabandabb. - Identical strings. A string is an anagram of itself, so
"abc"and"abc"returnstrue. - Comparing arrays with
==. This compiles but returnsfalsefor two separate arrays, even when they hold the same letters. - Forgetting to sort one of them. Sorting only
scompares a sorted array with a shuffled one, which almost never matches. - Missing
using System.Linq;. Without it,SequenceEqualisn't found and the code doesn't compile.
Testing
"anagram","nagaram"givestrue."rat","car"givesfalse."ab","abb"givesfalse."abc","abc"givestrue.
