这题最简单粗暴的方法就是依次枚举数组中的每一个成绩,判断分数小于等于该成绩的个数是否比大于该成绩的个数多。但是这个方法的时间复杂度为,这显然不是一个较优的解法
通过观察测试样例,我们不难看出,令学生个数为 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 方法对数组中的数据进行排序,时间复杂度为
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;
}