题目重点:map of maps存bigram计数,静态数据可预计算最佳后继。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 输入为已分词的sentence列表,不跨句边界计转移;大小写/标点归一化由调用方确定。
- 返回最多频后继,并列字典序最小;无后继词不在结果map里,查询时需定义unknown。
解题路线
- 每句相邻词(a,b)更新counts[a][b]。句尾不与下一句开头连接,避免伪造语言关系。
- 全部静态数据处理完后,每a扫描后继取最大count及稳定tie,预存best[a]使query期望O(1)。
- 动态更新才需要维护每词最高频及tie,删除事件可能让旧冠军下降,届时可用有序结构或重扫。不要为静态最大值强行维护每词堆。
手动走一遍
句["we","like","tea"]和["we","like","coffee"]:we最佳like;like两个后继并列选coffee。单词句无bigram;不同句之间tea→we不计。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
from collections import Counter
def predictor(sentences):
counts={}
for sentence in sentences:
for a,b in zip(sentence,sentence[1:]):counts.setdefault(a,Counter())[b]+=1
return {a:min(counter,key=lambda b:(-counter[b],b)) for a,counter in counts.items()}
复杂度
总token L建表期望O(L),后处理O(E),E不同bigram;存储O(E+V)。预计算后单query期望O(1)。
易错点与追问
容易失分的边界
- 用出现总频最高的词代替当前词的条件后继。
- 真实语言模型不止一个前词,bigram只是本接口统计,不代表完整NLP能力。
继续深挖
- 改为topK后继,预排序与每query heap成本如何比较?
- 时间衰减频次怎样避免每条查询更新所有历史计数?
