每日一题20220608

  1. 牛牛今年上幼儿园了,老师叫他学习减法,
    老师给了他5个数字,他每次操作可以选择其中的4个数字减1,
    减一之后的数字不能小于0,因为幼儿园的牛牛还没有接触过负数。
    现在牛牛想知道,自己最多可以进行多少次这样的操作。
    扩展问题来自leetcode 2141,掌握了这个题原始问题就非常简单了。
    来自阿里笔试。
    ————————————————
    版权声明:本文为CSDN博主「福大大架构师每日一题」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_48502062/article/details/125174820
/**
     * 选择数组里面的4个元素进行减一操作,使得到的结果不能为负数,求解最多可以减少多少次?
     * @param n    数组的个数
     * @param arr  数组
     * @return
     * 前缀和的思想  二分思想
     * 思路:如果有数小于x,那么他至少要被赦免x-a次,才能满足要求.所以,统计每个数需要被赦免的次数,如果这个次数总和大于x,那么这个x就无法满足要求。
     */
    public static long maxRunTime(int n,int[] arr){
         Arrays.sort(arr);
         int size = arr.length;
         long sums[]  = new long[size];
         sums[0] = arr[0];
         //前缀和的循环
         for (int i=1;i<size;i++){
             sums[i] = sums[i-1]+arr[i];
         }
         long l=0;
         long m=0;
         long r = sums[size-1]/n;
         long ans =1;
         while (l<r){
             m = (l+r)/2;
             if (ok(arr,sums,m,n)){
                 ans = m;
                 l = m+1;
             }else {
                 r = m-1;
             }
         }
         return ans;
    }

    /**
     *
     * @param arr   总的数组
     * @param sums  前缀和
     * @param time 平均值
     * @param num  总的数字个数
     * @return
     */
    private static boolean ok(int[] arr, long[] sums, long time, int num) {
        int l=0;
        int m=0;
        //定位下标
        int r = arr.length-1;
        //数组的长度
        int left = arr.length;
        while (l<=r){
            //中间位置下标
            m = (l+r)/2;
            if (arr[m]>=time){
                left=m;
                r = m-1;
            }else {
                l=m+1;
            }
        }
        num-=arr.length-left;
        //生效元素的前缀和
        long rest = left==0?0:sums[left-1];
        //统计每个数赦免次数和小于x
        return time*(long)num<=rest;
    }

posted @ 2022-06-08 21:04  一棵小萌新  阅读(62)  评论(0)    收藏  举报