- 牛牛今年上幼儿园了,老师叫他学习减法,
老师给了他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;
}