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

48 阅读4分钟

问题分析

这道题目要求我们找到一个分数线 xxx,使得:

  1. 晋级人数(得分大于 xxx)在区间 [m,n][m, n][m,n] 之间
  2. 淘汰人数(得分小于等于 xxx)也在区间 [m,n][m, n][m,n] 之间
  3. 如果满足条件的分数线 xxx 存在多个,返回最小的 xxx。
  4. 如果不存在满足条件的分数线,返回 −1-1−1。

解决思路

  1. 排序数组

    • 我们首先对分数数组 aaa 进行升序排序。
    • 这样可以方便地通过数组索引快速判断当前分数线 xxx 的晋级人数和淘汰人数。
  2. 枚举所有可能的分数线

    • 分数线 xxx 的候选值只能是数组 aaa 中的某个得分。因为得分位于两项之间的值并不会改变晋级或淘汰的分组。
    • 因此,我们只需要遍历数组 aaa,逐一将其每个元素作为候选分数线 xxx。
  3. 计算晋级人数和淘汰人数

    • 对于一个给定的分数线 x=a[i]x = a[i]x=a[i]:

      • 晋级人数:passed=k−(i+1)\text{passed} = k - (i + 1)passed=k−(i+1),表示 a[i+1],a[i+2],…,a[k−1]a[i+1], a[i+2], \dots, a[k-1]a[i+1],a[i+2],…,a[k−1] 的个数。
      • 淘汰人数:eliminated=i+1\text{eliminated} = i + 1eliminated=i+1,表示 a[0],a[1],…,a[i]a[0], a[1], \dots, a[i]a[0],a[1],…,a[i] 的个数。
  4. 验证条件

    • 如果同时满足:

      • m≤passed≤nm \leq \text{passed} \leq nm≤passed≤n
      • m≤eliminated≤nm \leq \text{eliminated} \leq nm≤eliminated≤n
    • 那么当前分数线 x=a[i]x = a[i]x=a[i] 是一个可行解。

  5. 选择最小分数线

    • 我们从小到大遍历数组 aaa,一旦找到满足条件的分数线 xxx,就立即返回。这样保证了返回的分数线是最小的。
  6. 返回结果

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

代码详解

def find_score_threshold(m: int, n: int, a: list) -> int:
    # 对数组排序
    a.sort()
    length = len(a)
    result = -1

    # 遍历每个分数线
    for i in range(length):
        # 当前分数线为 a[i]
        x = a[i]
        # 晋级人数(得分 > x)
        passed = length - (i + 1)
        # 淘汰人数(得分 <= x)
        eliminated = i + 1

        # 检查条件
        if m <= passed <= n and m <= eliminated <= n:
            result = x
            break  # 找到第一个符合条件的最小分数线,直接退出

    return result

代码核心逻辑

  1. 排序

    a.sort()
    
    • 将分数数组按从小到大的顺序排列,方便后续的遍历和人数计算。
  2. 遍历数组

    for i in range(length):
        x = a[i]  # 当前分数线
    
    • 每次将数组中的一个元素 a[i]a[i]a[i] 作为当前分数线。
  3. 计算人数

    passed = length - (i + 1)  # 晋级人数
    eliminated = i + 1        # 淘汰人数
    
    • 晋级人数为数组中得分大于当前分数线的元素个数。
    • 淘汰人数为数组中得分小于等于当前分数线的元素个数。
  4. 条件验证

    if m <= passed <= n and m <= eliminated <= n:
        result = x
        break  # 找到第一个满足条件的分数线,立即退出
    
    • 同时验证晋级人数和淘汰人数是否都在区间 [m,n][m, n][m,n] 之间。
    • 如果满足条件,记录分数线并退出循环。
  5. 返回结果

    return result
    
    • 如果找到符合条件的分数线,返回结果;如果没有,返回 −1-1−1。

测试用例详解

示例 1

输入:

m = 2, n = 3, a = [1, 2, 3, 5, 6, 4]

排序后:

a = [1, 2, 3, 4, 5, 6]

枚举分数线:

  • x=1x = 1x=1:晋级人数 = 5,淘汰人数 = 1,不满足条件。
  • x=2x = 2x=2:晋级人数 = 4,淘汰人数 = 2,不满足条件。
  • x=3x = 3x=3:晋级人数 = 3,淘汰人数 = 3,满足条件。

输出:

3

示例 2

输入:

m = 1, n = 2, a = [7, 8, 9, 3, 5]

排序后:

a = [3, 5, 7, 8, 9]

枚举分数线:

  • x=3x = 3x=3:晋级人数 = 4,淘汰人数 = 1,不满足条件。
  • x=5x = 5x=5:晋级人数 = 3,淘汰人数 = 2,不满足条件。
  • x=7x = 7x=7:晋级人数 = 2,淘汰人数 = 3,不满足条件。
  • x=8x = 8x=8:晋级人数 = 1,淘汰人数 = 4,不满足条件。

输出:

-1

示例 3

输入:

m = 1, n = 4, a = [7, 8, 9, 3, 5]

排序后:

a = [3, 5, 7, 8, 9]

枚举分数线:

  • x=3x = 3x=3:晋级人数 = 4,淘汰人数 = 1,满足条件。

输出:

3

时间复杂度与空间复杂度

  1. 时间复杂度

    • 排序:O(klog⁡k)O(k \log k)O(klogk),其中 kkk 是数组的长度。
    • 遍历数组:O(k)O(k)O(k)。
    • 总时间复杂度为 O(klog⁡k)O(k \log k)O(klogk)。
  2. 空间复杂度

    • 使用了少量临时变量,空间复杂度为 O(1)O(1)O(1)。

总结

通过排序和枚举,我们可以高效地找到满足条件的最小分数线,代码逻辑清晰,时间复杂度和空间复杂度都符合要求。