AI刷题132. 优秀项目组初选评比 题解 | 豆包MarsCode AI刷题

37 阅读5分钟

问题描述

公司正在进行优秀项目组评比的初选工作,参赛者有小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

这里我想到了两种解题思路,首先第一种是通过排序,再利用二分查找来确定可能的分数线。第一种方法的代码量比较多,但这里使用二分查找来优化查找过程,减少了不必要的遍历,逻辑更复杂但更高效。

  1. 排序:首先对得分列表 a 进行排序。排序后,我们可以通过二分查找来确定可能的分数线 x

  2. 二分查找

    • 初始化 left 为 0right 为 a 的最大值。

    • 在 [left, right] 区间内进行二分查找,每次取中间值 mid 作为分数线 x

    • 计算得分大于 mid 的项目组数量 count

    • 检查 count 是否在 [m, n] 区间内:

      • 如果在区间内,则更新 right 为 mid,继续查找更小的 x
      • 如果不在区间内,则更新 left 为 mid + 1,继续查找更大的 x
  3. 验证

    • 最终找到的 x 需要再次验证是否满足条件。

代码展示1

微信图片_20241125224708.png

1. 函数的作用

  • 函数 find_min_cutoff 用于找到一个最小的分数阈值 mid,使得得分列表中超过该阈值的项目组数量 count 在给定范围 [m, n] 之间。

2. 参数说明

  • m: 最少需要的符合条件的项目组数量。
  • n: 最多允许的符合条件的项目组数量。
  • a: 项目组得分列表(整数值)。

3. 算法整体流程

  1. 对列表 a 排序。
  2. 初始化二分查找的左右边界 leftright
  3. 通过二分查找确定最小的阈值 mid,使得大于 mid 的项目组数量符合条件 [m, n]
  4. 验证最终结果是否有效,返回对应的阈值或 -1

解题分析2

第二种方法也是需要先通过排序,但选取分数线使用了枚举法,即遍历排序后的分数列表,枚举每个可能的分数线对应的晋级数量。

  • 排序得分列表

    • 将得分列表 a 排序,确保分数按从低到高的顺序排列。便于通过索引定位分数线 xxx。
  • 枚举分数线候选值

    • 遍历排序后的分数列表,枚举每个可能的分数线对应的晋级数量 len(list)−i\text{len(list)} - ilen(list)−i:

      • 若该数量落在范围 [m,n][m, n][m,n] 内,返回对应的分数线。
  • 返回结果

    • 如果遍历完成后仍未找到满足条件的分数线,则返回 −1-1−1。

代码展示2

微信图片_20241125230305.png

1. 函数的作用

  • 函数 solution用于确定一个初选晋级分数线,使得得分大于的项目组数量在区间 [m,n][m, n][m,n] 之内。如果存在多个符合条件的分数线,返回其中最小的分数线。如果没有满足条件的分数线,返回 −1。

2. 参数说明

  • m: 表示晋级项目组数量的最小限制。
  • n: 表示晋级项目组数量的最大限制。
  • a: 包含所有项目组的得分列表。

算法整体流程

  1. 排序得分列表:
    使用 sorted(a) 对输入的得分列表进行升序排序。排序后可以方便地通过索引判断分数线对应的晋级项目组数量。

  2. 遍历可能的分数线位置:
    使用 for i in range(m, n+1) 遍历可能的分数线位置 i

  3. 返回满足条件的最小分数线:
    如果当前分数线位置 i满足条件,返回对应的分数。

  4. 返回结果:
    如果所有分数线都不满足条件,返回 −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)

结论

通过两种不同的解题方法,可以感受到使用不同算法的优缺点。在时间复制度和空间复杂度上,这两种方法没有差别。但是,在代码的可读性上,这道题使用枚举法明显比使用二分查找更为简洁明了,它的代码简洁、逻辑清晰,容易理解,而采用二分查找的代码稍微复杂一些。可是在某些情况下,枚举法的效率并不够高,所以如果想要进一步优化,这里就可以考虑使用二分查找的方法。所以,如果单是考虑这道题的解题的话,从整体来看,第二种解题方法即排序后采用枚举法是一个很好的解决方案,它的逻辑简单直接,容易理解和维护。