统计班级中的说谎者 题目解析 | 豆包MarsCode AI刷题

39 阅读3分钟

这题最简单粗暴的方法就是依次枚举数组中的每一个成绩,判断分数小于等于该成绩的个数是否比大于该成绩的个数多。但是这个方法的时间复杂度为O(n2)O(n^2),这显然不是一个较优的解法

通过观察测试样例,我们不难看出,令学生个数为 n,假设数组中的每一个成绩都不一样,如果 n 是奇数,那么说谎者的个数为 n/2+1;如果 n 是偶数,那么说谎者的个数为 n/2。我们可以拿题目中的其中一组测试样例来说明:

输入:A = [19, 27, 73, 55, 88]
输出:3

为了方便说明,可以先将数组内的数据进行排序:

A = [19, 27, 55, 73, 88]

显然,符合说谎者条件的成绩有55、73、88,共有3个,符合上述结论(3 == 5/2+1)

上面这个例子是 n 为奇数的情况,n 为偶数的情况不难分析

其实从上面的例子,我们就可以得出更优解法的第一个步骤:排序

我们可以使用 Java 中 Arrays 类的 sort 方法对数组中的数据进行排序,时间复杂度为O(nlogn)O(nlogn)

Arrays.sort(A);

为了获取学生的个数,也就是数组的长度,我们需要调用数组的 length 方法:

int n = A.length;

同时,根据我们在前文得出的结论,我们可以写出:

        int ans = 0;
        if (n % 2 == 0) { // even
            ans = n / 2;
        } else { // odd
            ans = n / 2 + 1;
        }

在前文得出的结论,我们其实做出了一个假设,也就是数组中的每一个成绩都不一样。但是数组中也是有多个成绩相同的可能的,所以接下来我们需要处理这种情况

在前面的分析里,我们可以看出来,说谎者其实都是成绩高于中位数的那部分学生,所以这部分学生里出现成绩相同的情况,处理的方法是和成绩不同的情况一样的。所以我们着重要处理的,其实是成绩小于等于中位数的那部分学生成绩相同的情况

我们可以定义一个中间下标 mid = n / 2,这个下标对应的值恰好是成绩高于中位数的那部分学生的最低成绩,或者我们可以用一个更简洁的表述:分数线。对于成绩小于等于中位数的那部分学生,只要成绩等于分数线,那么就说明这个学生也符合说谎者的条件

        int mid = n / 2;
        for (int i = mid - 1; i >= 0; i--) {
            if (A[i] < A[mid]) {
                break;
            }
            ans++;
        }
        return ans;

以下是全部代码:

    public static int solution(int[] A) {
        // Edit your code here
        int n = A.length;
        Arrays.sort(A);
        int ans = 0;
        if (n % 2 == 0) { // even
            ans = n / 2;
        } else { // odd
            ans = n / 2 + 1;
        }
        int mid = n / 2;
        for (int i = mid - 1; i >= 0; i--) {
            if (A[i] < A[mid]) {
                break;
            }
            ans++;
        }
        return ans;
    }