二分查找
线上报警问题分类
问题描述
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]
算法步骤
- 初始化用户数据:
- 将用户的实验命中情况转化为集合形式,便于快速判断是否命中某实验。
- 遍历查询条件:
- 对于每个查询条件,初始化计数器为 0。
- 遍历所有用户,对当前用户判断是否满足查询条件:
- 对于查询中的每个实验条件:
- 如果是正数,检查用户是否命中该实验。
- 如果是负数,检查用户是否未命中该实验。
- 如果当前用户满足所有条件,则计数器加 1。
- 对于查询中的每个实验条件:
- 返回结果
代码
def solution(n, m, q, arrayN, arrayQ):
user_experiments = []
for user in arrayN:
user_experiments.append(set(user[1:])) # 使用集合方便查找
results = []
for query in arrayQ:
count = 0
required_experiments = set()
forbidden_experiments = set()
# 解析查询条件
for exp in query[1:]:
if exp > 0:
required_experiments.add(exp)
else:
forbidden_experiments.add(-exp)
# 检查每个用户是否符合条件
for user_exp in user_experiments:
if required_experiments.issubset(user_exp) and forbidden_experiments.isdisjoint(user_exp):
count += 1
results.append(count)
return results
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]
)
- 时间复杂度:O(n×m+q×n×c)
- 空间复杂度:O(n×m)
糖果均匀分配问题
问题描述
小M从商店买了两种糖果,第一种有 aa 个,第二种有 bb 个。现在她想要将这些糖果分给班上的 nn 个小朋友,分配需要遵循以下规则:
- 每个小朋友必须且只能得到一种糖果(不能同时得到两种糖果)
- 每个小朋友至少要得到一个糖果
- 每种糖果至少要分给一个小朋友
- 为了尽可能公平,小M希望分到糖果最少的小朋友能得到尽可能多的糖果
请你帮助小M计算:在满足上述所有条件的前提下,分到糖果最少的小朋友最多能得到多少个糖果?
输入格式
- 输入包含三个整数 nn, aa, bb
- 其中 nn 表示小朋友的数量,aa 和 bb 分别表示两种糖果的数量
- 保证 1≤n≤1051≤n≤105,1≤a,b≤1051≤a,b≤105
输出格式
- 输出一个整数,表示在最优分配方案下,得到糖果最少的小朋友能得到的最大糖果数
- 如果无法按要求分配,输出 0
测试样例
样例1:
输入:
n = 5, a = 2, b = 3
输出:1
解释:可以给 2 个小朋友每人分 1 个第一种糖果,给 3 个小朋友每人分 1 个第二种糖果
样例2:
输入:
n = 4, a = 7, b = 10
输出:3
解释:可以给 2 个小朋友每人分 3 个第一种糖果(共 6 个,剩 1 个),给 2 个小朋友每人分 5 个第二种糖果。此时分到最少糖果的小朋友得到 3 个,且无法获得更优的分配方案
样例3:
输入:
n = 3, a = 3, b = 3
输出:1
解释:可以给 2 个小朋友每人分 1 个第一种糖果(剩 1 个),给 1 个小朋友分 3 个第二种糖果
解题思路
我们需要将两种糖果 a 和 b 分配给 n 个小朋友,满足以下条件:
- 每个小朋友只能得到一种糖果。
- 每个小朋友至少得到一个糖果。
- 每种糖果至少分给一个小朋友。
- 分到糖果最少的小朋友能得到尽可能多的糖果。
二分查找:我们可以使用二分查找来确定分到糖果最少的小朋友能得到的最大糖果数。设这个数为 k,我们需要检查是否存在一种分配方式使得每个小朋友至少得到 k 个糖果。
注意:边界条件:如果 a + b < n,则无法满足每个小朋友至少得到一个糖果的条件,此时应返回 0。
算法步骤
- 初始化二分查找的范围:最小值
left为1,最大值right为min(a, b) - 二分查找:
- 计算中间值
mid - 检查是否可以将
a和b分配给n个小朋友,使得每个小朋友至少得到mid个糖果 - 如果可以,尝试更大的
mid(即left = mid + 1) - 如果不可以,尝试更小的
mid(即right = mid - 1)
- 计算中间值
- 返回结果
代码
def solution(n: int, a: int, b: int) -> int:
def can_distribute(k: int) -> bool:
# 计算需要分配的糖果总数
total_candies_needed = k * n
# 检查是否可以分配
return (a // k) + (b // k) >= n
# 二分查找
left, right = 1, min(a, b)
while left <= right:
mid = (left + right) // 2
if can_distribute(mid):
left = mid + 1
else:
right = mid - 1
return right
if __name__ == '__main__':
print(solution(5, 2, 3) == 1)
print(solution(4, 7, 10) == 3)
print(solution(3, 3, 3) == 1)
print(solution(6, 4, 6) == 1)
print(solution(8, 5, 7) == 1)