问题描述
为了避免 AB 实验在迭代过程中导致系统崩溃,系统增加了监控报警功能,通知值班同学对意外情况立刻处理。
在报警的时间范围内,小M同学收到了 𝑁 名用户的反馈,每位用户编号为 1 到 𝑁。小M同学统计了用户命中实验的列表,其中第 𝑖 位用户命中了 𝑘𝑖个实验,第 𝑗 个实验的编号为 𝑎𝑖,𝑗。
小M同学需要对这些问题进行分类。根据先前的经验,小M同学会进行 𝑄 次询问尝试对问题进行分类,第 𝑖 次询问会给出一个序列 𝑏𝑖,1,𝑏𝑖,2,…,𝑏𝑖,𝑐𝑖,𝑐𝑖 表示第 𝑖 次查询的实验数量。当 𝑏𝑖,𝑗>0 时表示命中实验 ∣𝑏𝑖,𝑗∣,否则表示未命中实验 ∣𝑏𝑖,𝑗∣。小M同学需要得到符合这些条件的用户数。例如,序列 1, -2, 3 表示命中实验 1, 3 且未命中实验 2 的用户数量。
输入:
-
n:表示用户的数量。 -
m:表示实验的数量。 -
q:表示查询的次数。 -
arrayN:一个二维列表,表示每个用户的实验命中情况。arrayN[i]表示第i个用户的实验命中列表。arrayN[i][0]:表示第i个用户命中的实验数量。arrayN[i][1:arrayN[i][0]+1]:表示第i个用户命中的实验编号。
-
arrayQ:一个二维列表,表示每次查询的条件。arrayQ[i]表示第i次查询的条件。
arrayQ[i][0]:表示第i次查询的实验数量。arrayQ[i][1:arrayQ[i][0]+1]:表示第i次查询的实验编号。如果实验编号为正数,表示命中该实验;如果为负数,表示未命中该实验。
输出:
一个列表,表示每次查询符合条件的用户数量。
问题分析
这个问题的主要难点在题目的理解上,由于输入的信息很多,显得很繁琐,不知道从何入手。
但通过仔细分析,可以发现,最重要的两个输入信息是 arrayQ 和 arrayQ。
arrayN囊括了用户命中信息。输入中给出的n,是这个列表的长度,表示用户数量。arrayQ表明了小M同学查询的相关信息。输入中给出的q,也就是是这个列表的长度,表示小M同学查询的次数。m代表实验的数量,可以从arrayN、arrayQ中所含数字的绝对值的数量多少看出。
针对最重要的两个信息,这题要求的是对于 arrayQ 的每次查询条件,arrayN 中满足条件的用户数量,把这些记录下来形成一个列表输出。
代码书写
本题需要用到集合(set)及相关函数。首先需要把每个用户的实验命中情况转换为集合。
在样例中,可以看出用户可能会命中了多个相同的实验,使用集合可以实现自动去重,确保每个实验编号只被处理一次。
user = [set(arrayN[i][1:arrayN[i][0]+1]) for i in range(n)]
-
arrayN[i]表示第i个用户的实验命中列表。 -
arrayN[i][1:arrayN[i][0]+1]- 从
arrayN[i]的第 2 个元素开始,到第arrayN[i][0] + 1个元素为止的切片。 - 由于
arrayN[i][0]表示第i个用户命中的实验数量,这个切片包含了第i个用户命中的所有实验编号。
- 从
-
set(arrayN[i][1:arrayN[i][0]+1])将上述切片转换为集合(
set)。集合会自动去除重复的实验编号,确保每个实验编号只出现一次。 -
最后遍历从
0到n-1的所有用户,将其实验命中情况转换为集合,并添加到列表user中。
查询实现
对于每一次查询,我们可以用两个集合来表示查询条件,一个为命中实验,另一个储存非命中实验。
在
arrayQ中,非命中实验用负数表示,所以我们要在集合中加入它的相反数。
hit= set()
miss = set()
for exp in query[1:query[0]+1]:
if exp > 0:
hit.add(exp)
else:
miss.add(-exp)
检验每一个用户是否符合查询条件
count = 0
for user_exp in user:
if hit.issubset(user_exp) and miss.isdisjoint(user_exp):
count += 1
-
hit.issubset(user_exp):hit是查询中要求命中的实验集合。user_exp是当前用户的实验命中集合。issubset方法用于检查hit_experiments是否是user_exp的子集。它检查用户是否命中了查询中要求的实验部分。
-
miss.isdisjoint(user_exp):-
miss是查询中要求未命中的实验集合。 -
isdisjoint方法用于检查miss_experiments和user_exp是否不相交。用于判断两个集合是否包含相同的元素,如果没有返回 True,否则返回 False。在这里,函数检查用户是否未命中要求的实验部分。
-
完整代码
def solution(n, m, q, arrayN, arrayQ):
user = [set(arrayN[i][1:arrayN[i][0]+1]) for i in range(n)]
result = []
for query in arrayQ:
# 将查询条件分为命中实验和未命中实验
hit= set()
miss = set()
for exp in query[1:query[0]+1]:
if exp > 0:
hit.add(exp)
else:
miss.add(-exp)
# 统计符合条件的用户数量
count = 0
for user_exp in user:
if hit.issubset(user_exp) and miss.isdisjoint(user_exp):
count += 1
result.append(count)
return result
if __name__ == "__main__":
# Add your test cases here
print(
solution(
3,
3,
3,
[[2, 1, 2], [2, 2, 3], [2, 1, 3]],
[[2, 1, -2], [2, 2, -3], [2, 3, -1]],
)
== [1, 1, 1]
)