题目重点:顺序稳定且不提前读尽所有输入,迭代状态只保存必要去重。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- ID可哈希,blocked为固定快照;favorites与photos分别有序。
- 先输出全部有效favorites,再输出photos中未输出且未blocked者;重复ID只输出一次。
解题路线
- 依次遍历两个source,每ID先检查blocked再seen,通过才放seen并yield。整个算法不按ID排序,保留原到达顺序。
- yield暂停直到消费者要下一个;如果favorites是无限流,永远到不了普通photos,接口需要限制或定义公平交织,但那会改变“favorite全部优先”。
- blocked快照避免迭代中权限变化语义模糊;若blocked是实时权限,需每次输出前重新核对且讨论已输出内容无法撤回。
手动走一遍
favorite=[B,A,B],photos=[A,C,D],blocked={C}输出B,A,D。消费者只取第一项时不应预读完整photos;blocked和seen需要的读取仍可能让一次next跳过很多项。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def photo_iterator(favorites,photos,blocked):
blocked=frozenset(blocked)
seen=set()
for source in (favorites,photos):
for ident in source:
if ident not in blocked and ident not in seen:
seen.add(ident)
yield ident
复杂度
总读取N、有效输出D,期望O(N)时间、O(D+B)状态;单次next最坏可扫描大量被过滤项,不能声称每next最坏O(1)。
易错点与追问
容易失分的边界
- 只对各列表内部去重不够,还要跨列表去重。
- seen应只记真正输出的ID,特别当blocked规则扩展时需明确语义。
继续深挖
- hasNext怎样预取一个有效项又不重复消费?
- 独立两个iterator是否各自有seen,共享输入生成器会有什么限制?
