题目描述
思路解析动画文字版
直接统计字符频率和顺序无关。
比较相邻单词第一个不同字符,得到有向边;再拓扑排序。
比对 wrt / wrf · 推出第一条边 t→f:相邻两词 wrt 和 wrf 前两位相同,第 3 位 t≠f → 字典序里 t 排在 f 前 → 连一条有向边 t→f。
比对 wrf / er · 推出 w→e:下一对 wrf 和 er,第 1 位就不同:w≠e → 边 w→e。每对相邻词只贡献第一个不同字符那一条边。
四对词比完 · 建出完整约束图:再比 er/ett 得 r→t、ett/rftt 得 e→r。四条边连成一条链。入度:w=0,e/r/t/f 各=1。入度 0 的点没有任何字母必须排在它前面。
拓扑排序 · 入度 0 的 w 先出队:拓扑排序:w 入度 0,第一个进结果;删掉 w 的出边后,e 的入度降到 0,成为下一个候选。
依次出队 · 得字母表 wertf:沿链一路出队:w → e → r → t → f。拼起来就是这门火星语的字母表顺序 "wertf"。
一句话记住:比较相邻单词第一个不同字符,得到有向边;再拓扑排序。
边界三连:边界三连先过:空输入、单元素、重复或相等值。能过这三类,主逻辑才算站稳。
雷区 · 出现环就无解:雷区:若约束里出现环(比如又推出 e→w),说明字母顺序自相矛盾,拓扑排序会有点排不出来 → 返回空串 ""。无环才有唯一/合法顺序。
面试追问 1:比较相邻单词第一个不同字符,得到有向边;再拓扑排序。
面试追问 2:面试追复杂度时,不要只报 O,要把“每个元素进出几次”讲清楚。
面试追问 3:火星词典 不是孤题,它练的是 高级图 的状态设计。
这题学完不要乱跳,下一步去对应专题 /leetcode-animation/ds?k=graph 连刷同类题;卡住时用 AI 答疑问“我的状态定义哪里不稳”。
参考代码
class Solution: def alienOrder(self, words): from collections import defaultdict, deque graph = {ch: set() for w in words for ch in w} indeg = {ch: 0 for ch in graph} for a, b in zip(words, words[1:]): if len(a) > len(b) and a.startswith(b): return "" for x, y in zip(a, b): if x != y: if y not in graph[x]: graph[x].add(y) indeg[y] += 1 break q = deque([ch for ch in indeg if indeg[ch] == 0]) ans = [] while q: ch = q.popleft() ans.append(ch) for nxt in graph[ch]: indeg[nxt] -= 1 if indeg[nxt] == 0: q.append(nxt) return "".join(ans) if len(ans) == len(indeg) else ""复杂度
- 时间复杂度:O(V+E),V=字母数、E=约束边数;Kahn 拓扑(BFS出入队)每点每边各处理一次,无排序无堆
- 空间复杂度:O(V+E),邻接表存图 + 入度数组 + 队列
可套用的代码模板
这一步不是复读 火星词典 的参考答案,而是抽出能迁移的骨架:先定义状态,再按动画的核心分支更新。
# 1. 定义状态state = init()# 2. 按顺序读输入for x in data: update(state, x) # 只做本题允许的安全转移# 3. 从状态里取答案return answer(state)易错点
面试追问把动画讲成自己的话
追问这题的核心状态是什么?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
K 站中转内最便宜的航班
LeetCode 787 · 中等 · 沿着 高级图 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题