【青训营笔记创作活动】116 线上报警分类

77 阅读3分钟

问题描述

AB 实验作为推荐策略迭代的有力工具,经常会有新的实验上线,以及一些无效策略的下线。在这些迭代过程中,难免会遇到意料之外的情况,导致部分服务崩溃而不可用。为了避免系统的全面崩溃,工程师们会添加监控报警,确保第一时间通知到值班同学进行处理。

小M同学刚刚开始负责线上报警的值班工作。很快,她就收到了第一条报警日志。在报警的时间范围内,小M同学收到了 NN 名用户的反馈,每位用户编号为 11 到 NN。小M同学查询线上实验后,统计了用户命中实验的列表,其中第 ii 位用户命中了 kiki​ 个实验,第 jj 个实验的编号为 ai,jai,j​。

这些用户的反馈并不完全是由于一个问题造成的,因此小M同学需要对这些问题进行分类。根据先前的经验,小M同学会进行 QQ 次询问尝试对问题进行分类,第 ii 次询问会给出一个序列 bi,1,bi,2,…,bi,cibi,1​,bi,2​,…,bi,ci​​,cici​ 表示第 ii 次查询的实验数量。当 bi,j>0bi,j​>0 时表示命中实验 ∣bi,j∣∣bi,j​∣,否则表示未命中实验 ∣bi,j∣∣bi,j​∣。小M同学需要得到符合这些条件的用户数。例如,序列 1, -2, 3 表示命中实验 1, 3 且未命中实验 2 的用户数量。

小M同学初来乍到,希望你能帮她解决这个问题。


测试样例

样例1:

输入:n = 3, m = 3, q = 3, arrayN = [[2, 1, 2], [2, 2, 3], [2, 1, 3]], arrayQ = [[2, 1, -2], [2, 2, -3], [2, 3, -1]]
输出:[1, 1, 1]

样例2:

输入:n = 5, m = 4, q = 2, arrayN = [[3, 1, 2, 3], [1, 2], [2, 1, 4], [3, 2, 3, 4], [2, 1, 3]], arrayQ = [[3, 1, -4, 2], [2, -1, -3]]
输出:[1, 1]

样例3:

输入:n = 4, m = 3, q = 2, arrayN = [[1, 1], [2, 2, 3], [1, 3], [2, 1, 2]], arrayQ = [[1, -3], [2, 2, 3]]
输出:[2, 1]

解决思路

这道题可以拆解为以下几个步骤:

  1. 解析输入数据

    • n 是用户的数量,m 是实验的数量,q 是查询的次数。
    • arrayN 是每个用户命中的实验列表。
    • arrayQ 是查询条件列表,查询条件可以是正数(命中实验)或负数(未命中实验)。
  2. 数据表示和查询条件匹配

    • 用一个字典表示每个用户命中的实验,用集合存储实验编号便于快速查找。
    • 遍历每个查询条件,统计满足该条件的用户数量。
  3. 匹配逻辑

    • 对于每个查询条件(例如 [2, 1, -2]),分别检查每个用户是否符合:

      • 如果条件是正数,例如 1,则用户必须命中实验 1
      • 如果条件是负数,例如 -2,则用户不能命中实验 2
    • 若所有条件均满足,则统计该用户。

  4. 输出结果

    • 每个查询条件的匹配结果存储为一个数组,最终返回结果。
def solution(n, m, q, arrayN, arrayQ):
    # 将每个用户的命中实验列表转化为集合
    user_experiments = [set(user[1:]) for user in arrayN]
    
    # 存储结果
    result = []
    
    # 遍历每个查询条件
    for query in arrayQ:
        count = 0  # 记录符合条件的用户数量
        conditions = query[1:]
        
        # 遍历每个用户
        for user in user_experiments:
            match = True
            for cond in conditions:
                experiment = abs(cond)
                if cond > 0 and experiment not in user:  # 必须命中
                    match = False
                    break
                if cond < 0 and experiment in user:  # 必须未命中
                    match = False
                    break
            if match:
                count += 1
        result.append(count)
    
    return result