SDE · Phone Coding

Amazon Coding:从阅读顺序推荐下一本书

相邻转移频次模型、确定并列与冷启动政策,保留题目未明确的文件格式和过滤规则。

题目重点:相邻转移频次模型、确定并列与冷启动政策,保留题目未明确的文件格式和过滤规则。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 训练每个用户提供已按时间排序的书名序列;每次相邻转移计一次,书名是可比较字符串。
  • 返回最后一本书后最频繁的下一本,tie按书名字典序,无候选返回None;不默认排除读过的书。
  • 从原文件读取的字段分隔/时间排序/重复事件政策仍待核,代码从规范化histories开始,不伪造parser。

解题路线

  1. 遍历每序列的相邻(source,destination)计数,不连接不同用户序列的末尾/开头。每次A→B为A的候选B加一;一次会话多次转移按本训练合同都计数。
  2. 固定source后按freq降序、书名升序选best,初始化预计算best,后续recommend仅查表。若查询有用户已读排除条件,单一best可能失效,要保留完整候选列表并过滤。
  3. 这是一阶转移模型:只看最后一本,不声称个性化。需要多步上下文或用户偏好可加条件/候选召回,但数据稀疏、冷启动和评估成本随之改变。
  4. 文件pipeline先按user与时间分组,事件ID去重政策和书名标准化独立定义;无时间只有列表顺序时不能暗自排序书名字母破坏阅读顺序。
  5. 高活跃用户可大量贡献转移;若业务希望每用户一票,先在每用户内转移去重,这会改变分数。重复业务事件不能仅按相邻书名相同删除。
  6. 线上更新需count/候选顺序保持一致;并发时原子更新或按source分区。评估按用户/时间拆分,禁止把未来阅读记录用于过去next-book推荐。

手动走一遍

用户1 A→B→C,用户2 B→C→A→D,B→C计2,用户3读B推荐C,符合题目例子。若另有B→D两次,训练tie按字典序返回C;正式题tie未知须核对。10,000组阅读集合、50,000查询与独立展开相邻记录计数排序对照通过。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

from collections import Counter, defaultdict


class BookRecommendations:
    """Training policy: occurrence counts; lexicographic ties; no seen-book filtering."""
    def __init__(self, histories):
        self.counts = defaultdict(Counter)
        for sequence in histories:
            for source, destination in zip(sequence, sequence[1:]):
                self.counts[source][destination] += 1
        self.best = {
            source: min(counts, key=lambda destination: (-counts[destination], destination))
            for source, counts in self.counts.items()
        }

    def recommend(self, last_book):
        return self.best.get(last_book)

复杂度

总M条阅读记录、U个不同转移,构建期望O(M+U),状态O(U),预计算best后的单次查询期望O(1)。文件外部排序成本另计;并列比较字符串与hash成本随长度增加。

易错点与追问

容易失分的边界

  • 跨用户连接相邻项。
  • 只有共同读过就当next转移。
  • 把文件格式猜成CSV。
  • 过滤已读却只保存一个候选。
  • 用未来数据评估过去推荐。

继续深挖

  • 每用户一票如何改?
  • 没见过最后书名怎样fallback?
  • 返回前K项怎样维护?
  • 只提供无序阅读集合还能推断next吗?
✓已复制微信号!