Verifying an Alien Dictionary
EasyPrompt
In an alien language, surprisingly, they also use English lowercase letters, but possibly in a different order. The order of the alphabet is some permutation of lowercase letters.
Given a sequence of words written in the alien language, and the order of the alphabet, return true if and only if the given words are sorted lexicographically in this alien language.
Example 1:
Input: words = ["hello","leetcode"], order = "hlabcdefgijkmnopqrstuvwxyz"
Output: true
Explanation: As 'h' comes before 'l' in this language, then the sequence is sorted.Example 2:
Input: words = ["word","world","row"], order = "worldabcefghijkmnpqstuvxyz"
Output: false
Explanation: As 'd' comes after 'l' in this language, then words[0] > words[1], hence the sequence is unsorted.Example 3:
Input: words = ["apple","app"], order = "abcdefghijklmnopqrstuvwxyz"
Output: false
Explanation: The first three characters "app" match, and the second string is shorter (in size.) According to lexicographical rules "apple" > "app", because 'l' > '∅', where '∅' is defined as the blank character which is less than any other character (More info).
Constraints:
1 <= words.length <= 1001 <= words[i].length <= 20order.length == 26- All characters in
words[i]andorderare English lowercase letters.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach improves upon the brute-force method by pre-processing the order string. We create a mapping from each character to its rank (position) in the alien alphabet. This allows for constant-time lookups of a character's rank, making the overall comparison process much faster.
Algorithm
- Preprocessing: Create an integer array
orderMapof size 26. Iterate through theorderstring and populateorderMapsuch thatorderMap[character - 'a']stores the rank of the character. - Comparison: Iterate through adjacent pairs of words (
word1,word2) in thewordsarray. - Compare
word1andword2character by character. - For each pair of characters
c1andc2, get their ranks fromorderMapin O(1) time. - If
rank(c1) > rank(c2), the list is unsorted. Returnfalse. - If
rank(c1) < rank(c2), the pair is sorted. Move to the next pair of words. - Handle the prefix case: if
word1is longer thanword2andword2is a prefix ofword1, returnfalse. - If the loop finishes, return
true.
Walkthrough
To optimize the character comparison, we can first build a data structure that maps each character to its position in the order string. An array of size 26 is perfect for this, as we are dealing with lowercase English letters. This pre-computation step takes a small, fixed amount of time but allows subsequent character rank lookups to be done in O(1) time, significantly speeding up the main comparison logic.
class Solution { public boolean isAlienSorted(String[] words, String order) { int[] orderMap = new int[26]; for (int i = 0; i < order.length(); i++) { orderMap[order.charAt(i) - 'a'] = i; } for (int i = 0; i < words.length - 1; i++) { String word1 = words[i]; String word2 = words[i + 1]; int minLength = Math.min(word1.length(), word2.length()); boolean different = false; for (int j = 0; j < minLength; j++) { char c1 = word1.charAt(j); char c2 = word2.charAt(j); if (c1 != c2) { if (orderMap[c1 - 'a'] > orderMap[c2 - 'a']) { return false; } different = true; break; } } if (!different && word1.length() > word2.length()) { return false; } } return true; }}Complexity
Time
O(N * M + L), where N is the number of words, M is the maximum length of a word, and L is the length of the `order` string. The pre-computation takes O(L) time. The main comparison loop takes O(N * M) because we iterate through N-1 pairs and each comparison takes at most O(M) time with O(1) character rank lookups. Since L is a constant (26), the complexity is effectively O(N * M).
Space
O(L) or O(1), as we use an auxiliary array of size 26 to store the character rankings. Since the alphabet size is fixed, this is considered constant space.
Trade-offs
Pros
Highly efficient due to O(1) character rank lookups.
The dominant part of the complexity comes from iterating through the words, which is necessary.
Cons
Requires a small amount of extra space for the mapping.
This approach involves iterating through each adjacent pair of words in the input list and comparing them character by character. For each pair of differing characters, we find their positions in the order string using a linear search (indexOf) to determine their relative rank. If we find any pair of words that is out of order, we immediately return false.
Algorithm
- Iterate through the
wordsarray fromi = 0towords.length - 2. - For each
i, takeword1 = words[i]andword2 = words[i+1]. - Compare
word1andword2character by character up to the length of the shorter word. - At the first differing character, find their positions in the
orderstring usingindexOf(). - If the character from
word1has a higher index than the character fromword2, the list is unsorted, so returnfalse. - If the character from
word1has a lower index, this pair is sorted. Break the character comparison and check the next pair of words. - If the words are identical up to the length of the shorter word (one is a prefix of the other), check their lengths. If
word1is longer thanword2(e.g., "apple", "app"), the list is unsorted, so returnfalse. - If the entire loop completes, all pairs are sorted correctly. Return
true.
Walkthrough
The core idea is to verify the sorted property by checking every two adjacent words. If words[i] should come after words[i+1] for any i, then the array is not sorted. The comparison between two words is done character by character, and the relative order of two different characters is determined by finding their index in the order string.
class Solution { public boolean isAlienSorted(String[] words, String order) { for (int i = 0; i < words.length - 1; i++) { String word1 = words[i]; String word2 = words[i + 1]; int minLength = Math.min(word1.length(), word2.length()); boolean different = false; for (int j = 0; j < minLength; j++) { char c1 = word1.charAt(j); char c2 = word2.charAt(j); if (c1 != c2) { if (order.indexOf(c1) > order.indexOf(c2)) { return false; } different = true; break; } } if (!different && word1.length() > word2.length()) { return false; } } return true; }}Complexity
Time
O(N * M * L), where N is the number of words, M is the maximum length of a word, and L is the length of the `order` string (26). For each of the N-1 pairs of words, we might compare up to M characters. For each character comparison, we perform `indexOf`, which takes O(L) time.
Space
O(1), as we only use a few variables to store indices and characters, not dependent on the input size.
Trade-offs
Pros
Simple to understand and implement.
Requires no extra space.
Cons
Inefficient due to the repeated linear search (
indexOf) within theorderstring for every character comparison.
Solutions
Solution
class Solution { public boolean isAlienSorted ( String [] words , String order ) { int [] m = new int [ 26 ]; for ( int i = 0 ; i < 26 ; ++ i ) { m [ order . charAt ( i ) - 'a' ] = i ; } for ( int i = 0 ; i < 20 ; ++ i ) { int prev = - 1 ; boolean valid = true ; for ( String x : words ) { int curr = i >= x . length () ? - 1 : m [ x . charAt ( i ) - 'a' ]; if ( prev > curr ) { return false ; } if ( prev == curr ) { valid = false ; } prev = curr ; } if ( valid ) { break ; } } return true ; } }class Solution { public: bool isAlienSorted ( vector < string >& words , string order ) { vector < int > m ( 26 ); for ( int i = 0 ; i < 26 ; ++ i ) m [ order [ i ] - 'a' ] = i ; for ( int i = 0 ; i < 20 ; ++ i ) { int prev = - 1 ; bool valid = true ; for ( auto & x : words ) { int curr = i >= x . size () ? - 1 : m [ x [ i ] - 'a' ]; if ( prev > curr ) return false ; if ( prev == curr ) valid = false ; prev = curr ; } if ( valid ) break ; } return true ; } };class Solution : def isAlienSorted ( self , words : List [ str ], order : str ) -> bool : m = { c : i for i , c in enumerate ( order )} for i in range ( 20 ): prev = - 1 valid = True for x in words : curr = - 1 if i >= len ( x ) else m [ x [ i ]] if prev > curr : return False if prev == curr : valid = False prev = curr if valid : return True return TrueVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.