问题描述
公司正在进行优秀项目组评比的初选工作,参赛者有小C、小U、小R、小S、小M和小F的项目组。评委会已经根据他们提交的材料完成了打分,各个项目组的得分分别是s1,s2,s3,…,sks1,s2,s3,…,sk。评委们希望设定一个初选晋级的分数线xx,让所有得分大于xx的项目组晋级,其他的项目组将被淘汰。此外,评委们希望晋级的项目组数量和淘汰的项目组数量都在区间[m,n][m,n]之间。
显然,这个分数线xx可能不存在,也可能存在多个满足条件的分数线。如果不存在满足条件的xx,则输出−1−1;如果存在多个满足条件的分数线xx,则输出满足条件的最小分数线。
解题分析1
这里我想到了两种解题思路,首先第一种是通过排序,再利用二分查找来确定可能的分数线。第一种方法的代码量比较多,但这里使用二分查找来优化查找过程,减少了不必要的遍历,逻辑更复杂但更高效。
-
排序:首先对得分列表
a进行排序。排序后,我们可以通过二分查找来确定可能的分数线x。 -
二分查找:
-
初始化
left为0,right为a的最大值。 -
在
[left, right]区间内进行二分查找,每次取中间值mid作为分数线x。 -
计算得分大于
mid的项目组数量count。 -
检查
count是否在[m, n]区间内:- 如果在区间内,则更新
right为mid,继续查找更小的x。 - 如果不在区间内,则更新
left为mid + 1,继续查找更大的x。
- 如果在区间内,则更新
-
-
验证:
- 最终找到的
x需要再次验证是否满足条件。
- 最终找到的
代码展示1
1. 函数的作用
- 函数
find_min_cutoff用于找到一个最小的分数阈值mid,使得得分列表中超过该阈值的项目组数量count在给定范围[m, n]之间。
2. 参数说明
m: 最少需要的符合条件的项目组数量。n: 最多允许的符合条件的项目组数量。a: 项目组得分列表(整数值)。
3. 算法整体流程
- 对列表
a排序。 - 初始化二分查找的左右边界
left和right。 - 通过二分查找确定最小的阈值
mid,使得大于mid的项目组数量符合条件[m, n]。 - 验证最终结果是否有效,返回对应的阈值或
-1。
解题分析2
第二种方法也是需要先通过排序,但选取分数线使用了枚举法,即遍历排序后的分数列表,枚举每个可能的分数线对应的晋级数量。
-
排序得分列表:
- 将得分列表
a排序,确保分数按从低到高的顺序排列。便于通过索引定位分数线 xxx。
- 将得分列表
-
枚举分数线候选值:
-
遍历排序后的分数列表,枚举每个可能的分数线对应的晋级数量 len(list)−i\text{len(list)} - ilen(list)−i:
- 若该数量落在范围 [m,n][m, n][m,n] 内,返回对应的分数线。
-
-
返回结果:
- 如果遍历完成后仍未找到满足条件的分数线,则返回 −1-1−1。
代码展示2
1. 函数的作用
- 函数
solution用于确定一个初选晋级分数线,使得得分大于的项目组数量在区间 [m,n][m, n][m,n] 之内。如果存在多个符合条件的分数线,返回其中最小的分数线。如果没有满足条件的分数线,返回 −1。
2. 参数说明
m: 表示晋级项目组数量的最小限制。n: 表示晋级项目组数量的最大限制。a: 包含所有项目组的得分列表。
算法整体流程
-
排序得分列表:
使用sorted(a)对输入的得分列表进行升序排序。排序后可以方便地通过索引判断分数线对应的晋级项目组数量。 -
遍历可能的分数线位置:
使用for i in range(m, n+1)遍历可能的分数线位置 i -
返回满足条件的最小分数线:
如果当前分数线位置 i满足条件,返回对应的分数。 -
返回结果:
如果所有分数线都不满足条件,返回 −1。
比较
时间复杂度:
- 利用枚举法:排序的时间复杂度是
O(n log n),遍历的时间复杂度是O(n)。总体时间复杂度是O(n log n)。 - 利用二分查找:排序的时间复杂度是
O(n log n),二分查找的时间复杂度是O(log k),其中k是a的最大值。每次计算count的时间复杂度是O(n)。总体时间复杂度是O(n log n + n log k),通常k不会太大,所以总体时间复杂度接近O(n log n)。
空间复杂度:
- 利用枚举法:空间复杂度主要是排序的空间复杂度,为
O(n)。 - 利用二分查找:空间复杂度主要是排序的空间复杂度,为
O(n)。
结论
通过两种不同的解题方法,可以感受到使用不同算法的优缺点。在时间复制度和空间复杂度上,这两种方法没有差别。但是,在代码的可读性上,这道题使用枚举法明显比使用二分查找更为简洁明了,它的代码简洁、逻辑清晰,容易理解,而采用二分查找的代码稍微复杂一些。可是在某些情况下,枚举法的效率并不够高,所以如果想要进一步优化,这里就可以考虑使用二分查找的方法。所以,如果单是考虑这道题的解题的话,从整体来看,第二种解题方法即排序后采用枚举法是一个很好的解决方案,它的逻辑简单直接,容易理解和维护。