Problem overview
The function isAnagram receives two strings, s and t, and returns true when t can be made by rearranging the letters of s, using every letter exactly once. Both strings contain only lowercase English letters.
For s = "anagram" and t = "nagaram" the answer is true: both have three as and 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, with O(n) extra space for the sorted copies. Faster solutions exist, but this one uses sorting.
Approach: sort both, then compare
Two words are anagrams exactly when they have the same letters with the same counts and differ only in order. Sorting removes the order. If both strings are sorted into alphabetical order, anagrams turn into identical sequences, and strings that aren't anagrams stay different.
For "anagram" and "nagaram" the sorted form is aaagmnr for both. For "rat" and "car" the sorted forms are art and acr, which differ.
The result is simple: sort s, sort t, and test whether the two sorted sequences are equal. Strings of different lengths can't be anagrams, and the comparison handles that without a special check, because sequences of different lengths are never equal.
Step by step
- Sort
s.let sortedS = s.sorted()creates a constant holding the sorted characters.letfits because the value is never changed after it is created. - Sort
tthe same way intosortedT. Both strings get identical treatment so that the results can be compared position by position. - Compare and return.
sortedS == sortedTistruewhen the two arrays hold the same characters in the same order. Return that value directly.
The solution in Swift
func isAnagram(_ s: String, _ t: String) -> Bool {
let sortedS = s.sorted()
let sortedT = t.sorted()
return sortedS == sortedT
}
The Swift details worth a closer look:
sorted()returns a new array ofCharacter. AStringis a collection of characters, so"anagram".sorted()gives["a", "a", "a", "g", "m", "n", "r"], an[Character], not a string. To get a string back you would writeString(s.sorted()), which gives"aaagmnr", but the comparison doesn't need that step.- The original string is untouched. Strings in Swift are values, and
sorted()never changes the thing it is called on. The in-place version for mutable collections is calledsort(), and aStringdoesn't have it. - Arrays of characters compare with
==. Swift compares the lengths first and then the elements in order, so the result isfalseas soon as the arrays differ in length or in any position. - A function with no
class. In this lessonisAnagramis a free function, not a method, so there is noSolutionwrapper to write. - The
_before each parameter name means the call has no argument labels:isAnagram("rat", "car"). - A single-expression return could skip the temporary constants, as in
return s.sorted() == t.sorted(). The lesson keeps the named constants to show each step.
Complexity
Time: O(n log n + m log m), which is O(n log n) for strings of similar length. Here n and m are the lengths of s and t. Sorting s costs O(n log n), sorting t costs O(m log m), and comparing the two arrays walks them once, which is linear and smaller than the sorting.
Space: O(n + m). sorted() builds a new array for each string, so the extra memory grows with the input. The sort needs no further notable space.
Edge cases and common mistakes
- Different lengths.
isAnagram("a", "ab")isfalse. No length check is needed, because the two sorted arrays have different lengths. - Same letters, different counts.
"aab"and"abb"use the same set of letters but are not anagrams. Sorting givesaabandabb, which differ. A solution that only compares which letters appear would get this wrong. - Identical strings.
isAnagram("a", "a")istrue. A string is an anagram of itself. - Sorting only one string. Sorting
salone and comparing it with the rawtreturnsfalsefor"anagram"and"nagaram", becausetis not in alphabetical order. Both sides need the same treatment. - Comparing a string with an array.
s == t.sorted()doesn't compile, because one side is aStringand the other an[Character]. Either sort both sides, or convert withString(...). - Indexing strings by integer. Code that tries
s[0]fails, because aStringcan't be indexed with anInt. Thesorted()approach avoids index arithmetic altogether.
Testing
s = "anagram",t = "nagaram"returnstrue.s = "rat",t = "car"returnsfalse.s = "a",t = "ab"returnsfalse.s = "aab",t = "abb"returnsfalse.s = "a",t = "a"returnstrue.
