Problem overview
The function is_anagram receives two owned strings, s and t, and returns a bool: true when t can be formed by rearranging the letters of s, using every letter exactly once, and false otherwise. Both strings hold lowercase English letters and have between 1 and 50,000 characters.
For s = "anagram" and t = "nagaram" the answer is true: both strings contain three a, one each of g, m, n and r. For s = "rat" and t = "car" the answer is false, because t has a c that s lacks.
The lesson asks for O(n log n) time and O(n) extra space for the sorted copies. Faster approaches exist, but this lesson is about sorting.
Approach: sorting removes the order
An anagram has the same letters as the original in a different order. If you sort both strings, the order is gone and only the letters are left, so two anagrams turn into the same sorted sequence. In the example, "anagram" and "nagaram" both become aaagmnr. The strings "rat" and "car" become art and acr, which differ.
So the check is: sort both, then compare. Two sorted sequences are equal exactly when they contain the same letters with the same counts. Strings of different lengths can never match, and that case needs no separate check, as the comparison handles it by itself.
Step by step
- Collect the letters of
sinto a vector. AStringin Rust has nosortmethod, because it stores UTF-8 text, not a plain array of letters. Callings.chars().collect()into aVec<char>gives something that can be sorted. The variable is namedsorted_sand ismut, because sorting rearranges it in place. - Sort it with
sort(). The characters are ordered by their code points, which for lowercase letters is alphabetical order. - Do the same for
twith a vector namedsorted_t. Both strings get identical treatment, so their sorted forms can be compared position by position. - Return the comparison
sorted_s == sorted_t. Two vectors are equal when they have the same length and the same elements in the same order.
The solution in Rust
impl Solution {
fn is_anagram(s: String, t: String) -> bool {
let mut sorted_s: Vec<char> = s.chars().collect();
sorted_s.sort();
let mut sorted_t: Vec<char> = t.chars().collect();
sorted_t.sort();
return sorted_s == sorted_t;
}
}
Run on the examples, it returns true for ("anagram", "nagaram") and false for ("rat", "car").
The Rust details worth a closer look:
collect()needs a target type. The annotationVec<char>on the variable tellscollect()what to build. Without it, the compiler can't decide which collection you want.sort()works in place and returns(). It changes the vector it is called on, so the vector has to bemut, and the call is a statement of its own. Writinglet v = x.sort();would give you the unit value, not a sorted vector.- Strings can't be sorted directly. Calling
s.sort()on aStringis a compile error: no method namedsortfound for structString. Go through aVecof characters or bytes. chars()orbytes(). For lowercase English letters, collecting bytes into aVec<u8>and sorting that works equally well. The lesson useschar, which also stays correct for text outside ASCII.- Vectors compare with
==. The comparison goes element by element and stops at the first difference. A different length is an immediate mismatch. - Ownership. The function takes
Stringby value, butchars()only borrows, sosandtare untouched. The sorted vectors are new, separate copies.
Complexity
Let n be the length of s and m the length of t.
Time: O(n log n + m log m). Collecting each string is linear, sorting costs O(n log n) and O(m log m), and the final comparison is at most linear. When the lengths are equal, which is the only case that can be an anagram, this is O(n log n).
Space: O(n + m). The two vectors hold one char per letter. They are the sorted copies the lesson mentions.
Edge cases and common mistakes
- Different lengths.
("a", "ab")givesfalse. The vectors differ in length, so they can't be equal. - Same letters, different counts.
("aab", "abb")givesfalse. A check that only asks "does every letter oftappear ins?" would wrongly saytrue. Sorting keeps the counts. - Identical strings.
("a", "a")givestrue: a string is an anagram of itself. - Sorting only one of the strings. The unsorted vector is in original order, so the comparison would depend on how the letters were arranged, not on which letters they are.
- Forgetting
mut. Callingsort()on a vector declared withoutmutis a compile error.
Testing
s = "anagram",t = "nagaram"givestrue.s = "rat",t = "car"givesfalse.s = "a",t = "ab"givesfalse.s = "aab",t = "abb"givesfalse.s = "a",t = "a"givestrue.
