LeetCode 953. 验证外星语词典
题目描述


题意分析
给定 26 个小写字母在外星语言中的先后顺序,判断原单词数组是否按这套字典序非递减排列。单词可以相同;比较规则仍由第一个不同字符决定,前缀相同时短词在前。
解法:rank 映射 + 相邻单词比较
核心思路
[!blue]
字符原本的编码大小不能代表新字母表的顺序。先建立
rank[c - 'a'],记录字母c在order中的位置;之后比较两个字符,就比较它们的名次。字典序具有传递性,只需检查每对相邻单词:如果前一个都不大于后一个,整个数组就有序;任何一对逆序都足以判定失败。
比较
w1、w2时,从首字符开始扫描共同长度。相同就继续;首次出现不同字符时,若前词字符名次更大,立即返回false;若更小,这一对已经有序,应停止本对比较,继续检查后面的单词对。后续字符和词长都不能推翻首个不同字符的结论。只有共同部分完全相同时,才由长度决定大小:前词比后词长,说明后词是前词的严格前缀,顺序错误;否则这一对合法。代码用
decided区分“已由不同字符确定前词更小”和“共同部分全相同”,防止在前一种情况下错误地再按长度否定。
解题步骤
- 扫描
order,把每个字母映射为它的名次。- 依次取相邻两个单词,令
decided = false。- 从头比较共同长度内的名次。前词字符更大就返回
false;更小就令decided = true并停止本对扫描。- 若没有分出大小,检查前词是否更长,是则返回
false。- 所有相邻单词都通过后返回
true。只有一个单词或相邻两词完全相同,都不会构成逆序。
代码实现
class Solution {
public boolean isAlienSorted(String[] words, String order) {
// rank[字母] = 该字母在外星字母表中的名次。
int[] rank = new int[26];
for (int i = 0; i < order.length(); i++) {
rank[order.charAt(i) - 'a'] = i;
}
for (int i = 0; i < words.length - 1; i++) {
String w1 = words[i];
String w2 = words[i + 1];
int minLen = Math.min(w1.length(), w2.length());
// 已在共同可比较的部分遇到首个不同字符,并确定前词更小。
boolean decided = false;
for (int j = 0; j < minLen; j++) {
int r1 = rank[w1.charAt(j) - 'a'];
int r2 = rank[w2.charAt(j) - 'a'];
if (r1 < r2) {
decided = true;
break;
}
if (r1 > r2) {
return false;
}
}
// 公共部分全等时,短的必须排在前面。
if (!decided && w1.length() > w2.length()) {
return false;
}
}
return true;
}
}
func isAlienSorted(words []string, order string) bool {
// rank[字母] = 该字母在外星字母表中的名次。
rank := [26]int{}
for i, ch := range order {
rank[ch-'a'] = i
}
for i := 0; i < len(words)-1; i++ {
w1, w2 := words[i], words[i+1]
minLen := len(w1)
if len(w2) < minLen {
minLen = len(w2)
}
// 已在共同可比较的部分遇到首个不同字符,并确定前词更小。
decided := false
for j := 0; j < minLen; j++ {
r1 := rank[w1[j]-'a']
r2 := rank[w2[j]-'a']
if r1 < r2 {
decided = true
break
}
if r1 > r2 {
return false
}
}
// 公共部分全等时,短的必须排在前面。
if !decided && len(w1) > len(w2) {
return false
}
}
return true
}
复杂度分析
- 时间复杂度:$O(L+26)$,L 为全部单词总长度,每词至多参与相邻两次比较。
- 空间复杂度:$O(26)$,名次表。
关键点总结
[!green]
- 映射是“字母到名次”,使每次字符比较都符合给定字母表。
- 相邻单词逐对有序,通过传递性保证整个数组有序。
- 首个不同字符优先;只有共同部分全相同时才比较长度。
易错点总结
[!yellow]
- 直接比较字符编码,会忽略外星字母表的顺序。
- 首个不同字符已经确定前词更小后仍继续比较,可能被后面的字符误导。
- 一对单词合法时只能结束这一对的检查,不能直接返回整个数组有序。
- 忘记前缀长度判断,会接受长词排在其严格前缀之前的情况。
- 完全相同的单词符合非递减要求,长度相等不能判为失败。
相似题目
| 题目 | 难度 | 关联与区别 |
|---|---|---|
| 269. 火星词典 | 困难 | 本题已知字母序并验证单词排列,原题反过来从单词排列推导字母偏序。 |
转载与许可
许可
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!