题目重点:先定义任一标签匹配、全部标签匹配和回答优先级。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- questions映射questionID→标签集合,person给自己的标签;重复tag去重。
- 代码支持any交集非空与all人物标签全包含两种合同。优先级字段/更新规则未给,作为设计追问。
解题路线
- 建tag→questionIDs倒排。any查询取posting并集,all按最短posting开始交集,空tag在any返回空、all按空集子集定义返回全部。
- 倒排省掉与所有问题逐个比较;时间依真正访问posting量,不是无条件O(1)。热门标签仍会产生大量候选。
- 若按priority回答,可对候选构建堆;静态批量heapify O(C),取K O(KlogC)。动态priority用版本号惰性删过期项,并明确并发claim避免多人抢答同题。
手动走一遍
问题Q1={python,sql},Q2={python},人={python,sql}:any都匹配,all仅Q1。空标签人按all的数学合同匹配全部,但产品可能要求不匹配,必须显式改规则。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
class Index:
def __init__(self,questions):
self.tags={key:set(tags) for key,tags in questions.items()};self.postings={}
for key,tags in self.tags.items():
for tag in tags:self.postings.setdefault(tag,set()).add(key)
def match(self,tags,mode="any"):
tags=set(tags)
if mode=="any":
result=set()
for tag in tags:result.update(self.postings.get(tag,()))
return result
if mode!="all":raise ValueError("mode must be any/all")
if not tags:return set(self.tags)
lists=sorted((self.postings.get(tag,set()) for tag in tags),key=len)
result=set(lists[0])
for posting in lists[1:]:result.intersection_update(posting)
return result
复杂度
建索引O(A)空间/时间,A总标签关联。any O(Σposting长度),all实际集合交集成本相关;结果C也有Ω(C)输出。
易错点与追问
容易失分的边界
- all指问题标签都在人能力里还是人的标签都在问题里,方向不可混淆。
- 优先级高的问题如果不满足标签不能先弹堆后不计筛选成本。
继续深挖
- 删除问题和改标签怎样避免索引残留?
- priority加时间衰减时如何防止队列饥饿?
