问题描述
在小C的班级里,有 N 个学生,每个学生的成绩是 A_i。小C发现了一件有趣的事:当且仅当某个学生的成绩小于或等于自己的有更多人时,这个学生会说谎。换句话说,如果分数小于等于他的学生数量大于比他分数高的学生数量,则他会说谎。
现在,小C想知道班里有多少个学生会说谎。
样例1:
输入:
A = [100, 100, 100]
输出:3
解题思路
要解决这个问题,我们需要确定有多少学生的成绩是这样的:成绩小于或等于他们的学生数量大于成绩高于他们的学生的。
-
排序:首先对成绩数组
A进行排序。排序后,相同的成绩会相邻排列。 -
确定中间成绩:找到排序后数组的中间成绩
mid。这个成绩是中间值,即左边有left个成绩,右边有right个成绩。 -
调整
left和right指针:- 如果
left指针的前一个成绩与mid相同,说明有多个相同的成绩,需要向左移动left指针,直到遇到不同的成绩。 - 如果
right指针的后一个成绩与mid相同,同样需要向右移动right指针,直到遇到不同的成绩。
- 如果
-
计算说谎的学生数量:
left指针现在指向最后一个成绩小于mid的学生。right指针现在指向第一个成绩大于mid的学生。- 如果成绩大于
mid的学生数量少于成绩小于等于mid的学生数量,那么成绩为mid的学生就会说谎。因此,需要计算right-left-1(不包括mid本身)。 - 除了
mid成绩的学生外,所有成绩大于mid的学生也会说谎,因此需要加上A.length-right。
-
返回说谎的学生总数:将上述两部分相加,得到说谎学生的总数。
例如根据样例:
输入:
A = [25,12,8,19,19,16,20]
输出:4
排序后的数组是 [8, 12, 16, 19, 19, 20, 25]。中间成绩是19,left 指针指向第3个位置(成绩16),right 指针指向第5个位置(成绩20)。成绩小于或等于19的学生数量是4,成绩大于19的学生数量是2。由于4大于2,中间成绩的学生说谎,另外还有3个成绩大于19的学生也说谎。因此,说谎的学生总数是4。
代码
public static int solution(int[] A) {
int res=0;
Arrays.sort(A);
int left=A.length/2, right=A.length/2;
int mid=A[A.length/2];
if(left>0&&A[left-1]==A[left]){
while(left>0&&A[left-1]==mid){
left--;
}
}
if(right<A.length-1&&A[right]==A[right+1]){
while(right<A.length-1&&A[right+1]==mid){
right++;
}
}
left-=1;
right+=1;
if(A.length-right<right){
res=res+right-left-1;
}
res+=A.length-right;
return res;
}
```