LeetCode 676中等Trie
实现一个魔法字典 图解题解
这道题到底在问什么
实现 MagicDictionary 类: MagicDictionary() 初始化对象 void buildDict(String[] dictionary) 使用字符串数组 dictionary 设定该数据结构, dictionary 中的字符串互不相同 bool search(String searchWord) 给定一个字符串 searchWord ,判定能否只将字符串中 一个 字母换成另一个字母,使得所形成的新字符串能够与字典中的任一字符串匹配。如果可以,返回 true ;否则,返回 false 。
- buildDict/search
- ["hello","leetcode"], search("hhllo")
- 输出
- true
先想最直接的笨办法
图/Trie 状态跟着代码走:推进语句是:if diff == 1:。处理过的部分不再重新枚举。(动画第 10 步)
最优解:一步一步想明白
- 3下面 9 步动画会按主解代码推进,而不是泛泛讲题型。
- 4先读清 实现一个魔法字典 的输入输出图/Trie 状态跟着代码走:先把示例输入映射到代码参数:def __init__(self):。
- 5self.words = [];self.words = dictionary图/Trie 状态跟着代码走:开局只立住必要变量:self.words = [];self.words = dictionary。
- 6for word in self.words:图/Trie 状态跟着代码走:主流程从这里开始:for word in self.words:。
- 7if len(word) != len(searchWord):图/Trie 状态跟着代码走:题目条件落到这一行:if len(word) != len(searchWord):。
- 8diff += 1图/Trie 状态跟着代码走:对应代码:diff += 1。这一行决定当前轮对答案有什么贡献。
- 9必须恰好 1 处差异图/Trie 状态跟着代码走:边界跟着代码看:if diff > 1:。
- 10if diff == 1:图/Trie 状态跟着代码走:推进语句是:if diff == 1:。处理过的部分不再重新枚举。
- 11return False图/Trie 状态跟着代码走:到这里,diff 已经能表达题目要求。
- 12return:return False图/Trie 状态跟着代码走:最后检查返回形态:返回值、原地修改或设计类状态,要和 LeetCode 判题方式一致。
- 15记住这题的代码骨架:题意约束先落到状态变量,再用循环或递归维护它。
⚠️ 容易写错的地方
✗ 错:允许 0 处差异
✓ 对:必须恰好 1 处差异
原词完全相同不算成功
✗ 错:长度不同也比较
✓ 对:长度必须相同
只能修改一个字符,不能增删
完整代码(Python)
Python
class MagicDictionary:
def __init__(self):
self.words = []
def buildDict(self, dictionary):
self.words = dictionary
def search(self, searchWord):
for word in self.words:
if len(word) != len(searchWord):
continue
diff = 0
for a, b in zip(word, searchWord):
if a != b:
diff += 1
if diff > 1:
break
if diff == 1:
return True
return False复杂度
时间复杂度
O(words * L)
逐词比较
空间复杂度
O(words * L)
保存字典
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 实现一个魔法字典 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这道题为什么用「Trie」,换最直接的暴力解会差在哪?+
Trie抓住了本题的结构特征,把暴力解里重复的工作省掉;暴力解通常要多嵌套一层枚举,数据一大就超时。具体对比见上文「暴力解及其卡点」与「最优解逐步推演」两节。
时间复杂度为什么是 undefined?怎么推出来的?+
按上文复杂度小节的推导,时间复杂度为 undefined。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。