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

55 阅读1分钟

题目解析

公司正在进行优秀项目组评比的初选工作,每个项目组的得分已知。评委希望设定一个晋级分数线 xx,使得得分大于 xx 的项目组晋级,而得分小于等于 xx 的项目组淘汰。

要求晋级的项目组数量和淘汰的项目组数量均满足区间 [m,n][m, n]。需要根据得分数组 aa 找到满足条件的最小分数线 xx。若不存在这样的 xx,输出 1-1


思路分析

  1. 排序简化判断条件

    • 对得分数组 aa 排序,方便直接以每个得分为候选分数线 xx
    • 计算得分大于 xx 和小于等于 xx 的人数只需统计数组中间的索引位置。
  2. 二分查找

    • 候选分数线 xx 应为数组中的某个元素。
    • 使用二分查找快速定位满足条件的最小 xx
    • 每次二分时,判断当前分数线是否符合条件:
      • 晋级人数(得分大于 xx)和淘汰人数(得分小于等于 xx)均满足区间 [m,n][m, n]
    • 若符合条件,记录当前分数线并继续尝试更小的 xx;否则根据条件调整查找范围。
  3. 特殊情况

    • 如果遍历所有分数后仍无满足条件的 xx,输出 1-1

代码实现

import java.util.Arrays;

public class Main {
    public static int solution(int m, int n, int[] a) {
        // 1. 排序
        Arrays.sort(a);
        int length = a.length;
        int result = -1;

        // 2. 二分查找
        int left = 0, right = length - 1;
        while (left <= right) {
            int mid = (left + right) / 2;
            int x = a[mid];

            // 计算晋级和淘汰人数
            int greater = length - (mid + 1); // 得分大于 x 的数量
            int lesserOrEqual = mid + 1; // 得分小于等于 x 的数量

            // 判断是否满足条件
            if (greater >= m && greater <= n && lesserOrEqual >= m && lesserOrEqual <= n) {
                result = x; // 更新满足条件的分数线
                right = mid - 1; // 尝试找更小的分数线
            } else if (greater < m) {
                // 晋级人数太少,降低分数线
                right = mid - 1;
            } else {
                // 晋级人数太多,提升分数线
                left = mid + 1;
            }
        }

        return result;
    }

    public static void main(String[] args) {
        // 测试用例
        System.out.println(solution(2, 3, new int[]{1, 2, 3, 5, 6, 4}) == 3);
        System.out.println(solution(1, 2, new int[]{7, 8, 9, 3, 5}) == -1);
        System.out.println(solution(1, 4, new int[]{7, 8, 9, 3, 5}) == 3);
    }
}

代码详解

  1. 排序

    • 使用 Arrays.sort(a) 将数组按升序排序。
    • 排序后,对于任意分数 xx,其左侧为淘汰项目组,右侧为晋级项目组。
  2. 二分查找

    • 定义初始左右边界 left = 0, right = length - 1
    • 中间位置 mid 对应的分数 xx 是当前候选分数线。
    • 对每个候选分数线 xx
      • 计算晋级人数 greater = length - (mid + 1)
      • 计算淘汰人数 lesserOrEqual = mid + 1
      • 检查 greaterlesserOrEqual 是否都满足 [m,n][m, n]
        • 若满足,更新结果为当前分数线 xx,并继续向左搜索更小的分数线。
        • 若晋级人数不足,说明 xx 过高,降低分数线范围。
        • 若晋级人数过多,说明 xx 过低,提高分数线范围。
  3. 返回结果

    • 若找到满足条件的 xx,返回结果。
    • 若查找结束后未找到,返回 1-1

时间复杂度

  1. 排序

    • 排序操作的时间复杂度为 O(klogk)O(k \log k),其中 kk 是得分数组的长度。
  2. 二分查找

    • 二分查找最多执行 O(logk)O(\log k) 次。
    • 每次计算晋级和淘汰人数需要 O(1)O(1) 时间。

总时间复杂度为:
O(klogk)+O(logk)=O(klogk)O(k \log k) + O(\log k) = O(k \log k)


总结

  1. 优点

    • 利用排序和二分查找,使得算法高效,能快速定位满足条件的最小分数线。
  2. 局限

    • 对于边界情况,例如得分数组较小或分数分布不均匀时,可能无满足条件的分数线,需提前考虑输出 1-1
  3. 扩展

    • 可以进一步优化统计过程,例如通过预处理前缀和数组快速计算晋级/淘汰人数。

这套方法逻辑清晰、性能良好,是解决类似区间筛选问题的通用方案。