题目重点:流式读文件计算最高频单词,明确大小写、标点、Tie与大词表的外部聚合。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 训练ASCII字母连续串为词、小写归一,标点/数字分隔,n非负,返回(word,count)按count降序再word升序;这不是语言通用分词。
- 输入行迭代,不要求实际给文件即可写处理接口;超长单行仍占缓冲。
解题路线
- 逐行正则取tokens,Counter更新,不read全文件字符串。casefold/Unicode策略若不同应替换词定义,不在无合同下把don’t合成一个词。
- TopN用nsmallest key=(-count,word),避免排序所有D不同词;heap保留最好的N,输出符合tie。N0空,N>D返回全部。
- 精确词频仍需O(D)计数字典,流式只省原文整体存储,不意味着总内存常数。词表很大可外部分区/排序归并聚合。
- 近似heavy-hitter可以减状态,但不能默默给精确TopN题近似答案。若允许误差,要说明候选结构、频次估计与排名不确定。
- 多文件并行局部Counter后按词归并,全局TopN必须先合完整词频,不能只合每文件N个保证精确:某词在每文件第N+1可能全局第一。
手动走一遍
Apple, apple! BANANA得到apple2、banana1;相同频次cat/dog按cat先。a1b按训练分成a与b,不是单词a1b,词定义必须明确。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
import re,heapq
from collections import Counter
def top_words(lines,n):
"""ASCII alphabetic tokens, lowercase; punctuation splits; tie word ascending.
Input streamed by line. Exact counts need O(distinct words) state.
"""
if n<0:raise ValueError('nonnegative n')
counts=Counter()
for line in lines:
counts.update(token.lower() for token in re.findall(r'[A-Za-z]+',line))
return heapq.nsmallest(n,counts.items(),key=lambda p:(-p[1],p[0]))
复杂度
L文本字符/D不同词,token扫描O(L),TopN通常O(D log(min(N,D)+1)),精确计数O(D)空间与单行/token缓冲。结果N项空间另计。
易错点与追问
容易失分的边界
- 读完整文件后再Counter丢掉流式收益。
- 并列不定义输出使测试与实现随机不一致。
- 各分片仅保留TopN可能漏全局高频词。
继续深挖
- Unicode英文外语言分词怎样替换,并量测内存?
- 如果需要实时动态删除旧文件贡献,计数和候选回补怎样维护?
