问题描述 公司正在进行优秀项目组评比的初选工作,参赛者有小C、小U、小R、小S、小M和小F的项目组。评委会已经根据他们提交的材料完成了打分,各个项目组的得分分别是 s 1 ,s 2 ,s 3 ,…,s k 。评委们希望设定一个初选晋级的分数线 𝑥 x,让所有得分大于 𝑥 x的项目组晋级,其他的项目组将被淘汰。此外,评委们希望晋级的项目组数量和淘汰的项目组数量都在区间 [ 𝑚 , 𝑛 ] [m,n]之间。
显然,这个分数线 𝑥 x可能不存在,也可能存在多个满足条件的分数线。如果不存在满足条件的 𝑥 x,则输出 − 1 −1;如果存在多个满足条件的分数线 𝑥 x,则输出满足条件的最小分数线。
测试样例
示例 1:
输入:m = 2, n = 3, a = [1, 2, 3, 5, 6, 4] 输出:3
示例 2:
输入:m = 1, n = 2, a = [7, 8, 9, 3, 5] 输出:-1
示例 3:
输入:m = 1, n = 4, a = [7, 8, 9, 3, 5] 输出:3
Python代码为:
def solution(m: int, n: int, a: list) -> int: # 对得分列表进行排序 a.sort()
# 遍历可能的分数线 x
for x in range(min(a), max(a) + 1):
# 计算晋级和淘汰的项目组数量
count_above_x = sum(1 for score in a if score > x)
count_below_x = len(a) - count_above_x
# 如果满足条件,返回 x
if m <= count_above_x <= n and m <= count_below_x <= n:
return x
# 如果遍历完所有可能的 x 都没有找到满足条件的,返回 -1
return -1
if name == 'main': print(solution(2, 3, [1, 2, 3, 5, 6, 4]) == 3) print(solution(1, 2, [7, 8, 9, 3, 5]) == -1) print(solution(1, 4, [7, 8, 9, 3, 5]) == 3)
思路提示:
问题理解
你需要找到一个分数线 x,使得得分大于 x 的项目组数量和得分小于等于 x 的项目组数量都在给定的区间 [m, n] 内。 如果不存在这样的 x,则返回 -1。如果存在多个满足条件的 x,则返回最小的那个。
数据结构选择
列表:用于存储项目组的得分。
排序:对得分列表进行排序,以便更容易计算晋级和淘汰的项目组数量。
算法步骤
排序: 对得分列表 a 进行排序。 遍历可能的分数线 x: 从得分列表的最小值到最大值遍历所有可能的分数线 x。
计算晋级和淘汰的项目组数量: 对于每个 x,计算得分大于 x 的项目组数量 count_above_x。 计算得分小于等于 x 的项目组数量 count_below_x。
判断是否满足条件: 检查 count_above_x 和 count_below_x 是否都在区间 [m, n] 内。 如果满足条件,返回当前的 x。
返回结果: 如果遍历完所有可能的 x 都没有找到满足条件的,返回 -1。
优化算法的时间复杂度
排序: a.sort() 二分查找: 初始化左右边界 left 和 right。 在 while 循环中,计算中间值 mid。 计算 mid 对应的晋级和淘汰的项目组数量。 根据条件调整左右边界。
最终检查: 检查最终的 left 是否满足条件。
时间复杂度 排序:O(n log n) 二分查找:O(log n) 计算晋级和淘汰的项目组数量:O(n) 总体时间复杂度为 O(n log n),相比于原来的 O(n^2) 有了显著的提升。
总结反思:
对问题的理解十分重要,要能把实际问题转化成代码思路正确解出,合理减少时间和空间复杂度。