蓝桥杯——最少刷题数(JAVA)

题目:

小蓝老师教的编程课有 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

评测用例规模与约定

对于 30% 的数据, 1≤N≤1000,0≤Ai​≤1000.

对于 100% 的数据, 1≤N≤100000,0≤Ai​≤100000.

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 512M

代码: 

import java.util.Arrays;
import java.util.Scanner;

public class zui_shao_shua_ti_shu {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int n,mid;                   //n个学生,mid是中间值
        n=sc.nextInt();
        int [] arr=new int[n];       //存放每个学生做题数。
        int [] a=new int[n];         //将arr数组复制一份进行排序
        int [] result=new int[n];     //存储结果
        for (int i=0;i<n;i++){
            arr[i]=sc.nextInt();
            a[i]=arr[i];            //输入并复制。
        }
     kuaipai(a,0,a.length-1);      //用快排进行排序,必须用快排否则会超时几毫秒。
        mid=a[n/2];   
        int b=0;                   //判断当刷题数比中间值小时结果是否需要加一(默认不加)
        int c=0;                   //判断结果等于中间值时是否需要加一(默认不加)
        int bigger=0;
        int smaller=0;
        for (int i = 0; i < n; i++) {
            if (arr[i]>mid){
                bigger++;
            }
            if (arr[i]<mid){
                smaller++;          //计算比中间值大的和小的个数
            }

        }
        if (bigger>=smaller){
            b=1;                
        }
        if (bigger>smaller){
            c=1;
        }
        for (int i=0;i<n;i++){
            if (arr[i]<mid){
                result[i]=mid+b-arr[i];
            }else {
                if (arr[i] == mid) {
                    result[i] = c;
                }
                else {
                    result[i]=0;
                }
            }
            System.out.print(result[i]+" ");     //判断并输出
        }


    }
    public static void kuaipai(int [] a,int l,int r){   //快排
        if (l>=r){
            return;
        }
        int low=l;
        int high=r;
        int pivot=a[l];
        while(low<high){
            while(a[high]>=pivot&&low<high){
                high--;
            }
            while(a[low]<=pivot&&low<high){
                low++;
            }
            if (low<high){
                int temp=a[high];
                a[high]=a[low];
                a[low]=temp;
            }

        }
        a[l]=a[low];
        a[low]=pivot;
        kuaipai(a,l,low-1);
        kuaipai(a,low+1,r);
    }
}

思路:首先想到的是依靠中间值进行解题,第一次写的代码忽略了中间值可能重复,只通过了3个用例,然后开始改进,这里举几个例子:

3 4 5 6 6 6 7 8 9

如果学生刷题数是这个数组,中间值为6。

其中比6大的有3个比6小的也有3个如果第一个做三道题的学生做到中间值6那么比6小的有2个比6大的有3个不符合要求。刷题数正好是6的同学一道题也不用刷。

3 4 6 6 7 8 9

这个例子比6小的有2个比6大的有3个,所以刷6个题的同学依然要再刷一题才符合要求。

题目中要求比他多的学生数不超过刷题比他少的学生数,那么我们将数组排序中间值肯定是一个分水岭,接下来就需要考虑特殊情况找规律了。

然后呢这道题一开始我用的是Arrays.sort进行排序但发现有三个用例过不去,又尝试了几次发现过不去的三个用例中有几次过去了用时是九百多毫秒,然后就觉得可能程序只是满了几毫秒而导致超时,只要找到一个优化的点应该就能过去了。然后我将排序改成了快排刚好通过

 

快排虽然写着麻烦些但对计算机来说速度快很多,遇到这种情况的时候很管用,所以快排可以不用但一定要会写。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值