问题描述:
小蓝老师教的编程课有N名学生,编号依次是 1…N。第i号学生这学期
刷题的数量是Ai 。
对于每一名学生,请你计算他至少还要再刷多少道题,才能使得全班刷题
比他多的学生数不超过刷题比他少的学生数。
输入格式 :
第一行包含一个正整数N
第二行包含N个整数:A1 ,A2 ,A3 ,…AN .
输出格式:
输出N个整数,依次表示第 1…N号学生分别至少还要再刷多少道题。
样例输入
5
12 10 15 20 6
样例输出
0 3 0 0 7
额外样例:
输入样例1:
3
3 3 3
样例输出1:
0 0 0
输入样例2:
4
4 3 1 3
输出样例2:
0 0 3 0
解题思路:
首先,对于本题,我们很容易联想到找到这组数据的中间数。中间数左边的数比它小,中间数右边的数比他大,那显然就需要将数组排序了。
由于中间数的位置非常的特别,接下来我将要分情况对中间数的位置进行分析:
1.当数组的元素个数为奇数个时:
以 1 2 3 4 5来举例(示例一):
中间数的坐标:5/2 = 2对应的元素为3,恰好在数组中间
2.当数组元素个数为偶数个时:
以 1 2 3 4来举例(示例二):
中间数的坐标:4/2 = 2对应元素为3,中间数右边元素比左边元素少1个
再经过一些推理分析很容易得出:中间数组左边元素个数 - 中间元素右边元素个数= 0或1
值得注意的是当取的数在中间数的左边时,中间数左边元素要少一个,再结合上一条的结论很容易分析出取出的数要么等于中间数,要么比中间数大1。
当取出的数比中间数大的话当然就输出零喽。
例如:示例一,二中取1,为了达到题目要求至少还要刷3道题,示例二,为了达到要求还要刷2道题。
这样一般样例就可以解决了。
特殊样例:
1 3 3 4
其中中间数为3,但是与中间数相等地数不止一个,此时再取1的话就不能简单的让再刷题的数量等于3-1了。
这时不妨将两个3都视为中间数,再次统计中间数左边,右边的数量,再和上述一般样例一样根据取数的不同位置进行输出结果,无非就是用了一下整体思想。
理论成立代码如下:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int a[] = new int[n];
int b[] = new int[n];
for(int i = 0;i < n;i++) {
a[i] = sc.nextInt();
b[i] = a[i];
}
Arrays.sort(b);//对数组b排序
int middlenumber = b[n/2];//选取中间数
int left = 0;
int right = 0;
for(int i = 0;i < n;i++) {
if(i< n/2&&b[i] == middlenumber)//左边部分与中间数相等的
left++;
else if(i > n/2&&b[i]==middlenumber)//右边部分与中间数相等的
right++;
}
int L = n/2 - left;//比中间数小的数量
int R = n - n/2 - right - 1;//比中间数大的数量
int flag = (R - L) >= 0?1:0;//如果取的数在中间数的左边,那么左边要减去这个数L=L-1
for(int j = 0;j < n - 1;j++) {
if(a[j] < middlenumber)//取的数在左边
System.out.print(middlenumber - a[j] + flag + " ");
else if(a[j] == middlenumber && R-L > 0)//取的数在中间
System.out.print(middlenumber - a[j] + 1 +" ");
else//取的数在右边
System.out.print(0+" ");
}
if(a[n-1] < middlenumber)
System.out.print(middlenumber - a[n-1] + flag);
else if(a[n-1] == middlenumber && R-L > 0)
System.out.print(middlenumber - a[n-1] + 1);
else
System.out.print(0);
}
}