您的位置:首页 > 其它

LintCode 最大平均值子数组

2017-10-23 17:10 337 查看
给出一个整数数组,有正有负。找到这样一个子数组,他的长度大于等于 k,且平均值最大。

注意事项

保证数组的大小 >= k

样例

给出 nums = [1, 12, -5, -6, 50, 3], k = 3

返回 15.667 // (-6 + 50 + 3) / 3 = 15.667

参考了别人的想法,利用二分法,依然不是对数组中元素的二分,而是对一个区间的二分,逐渐找到结果。题目所求平均值一定是在 数组中最小值min和最大值max之间的一个数,所以对区间[min,max]二分查找。

如何判断是在mid左侧继续查找还是右侧继续查找,我们需要判断对于当前的假设结果mid(即假设的平均值),在数组中是否存在一个长度大于等于k的子数组,其平均值比mid大。当然不能枚举,我们用一个辅助数组d,把原数组中每个数与mid的差的前缀和存储起来(利用前缀和的问题还有这个最接近零的子数组和),如果数组d中,存在d[i]-d[j]>=0,而且i-j>=k ,那么说明原数组nums[j] 到nums[i] 这个子数组的平均值大于等于mid,接下来就要在[mid,max]中继续找,否则在[min,mid]中继续找。在判断d[i]-d[j]>=0时,我们用一个最小是preMin来代替d[j],preMin指的是数组d中,在d[i]之前,并且满足i-j>=k的最小值。(因为我们要判断是否存在一个误差大于0,所以我们只关心任意两个误差前缀和相减之后的最大值,所以那个被减数越小越好)。

代码如下:

ublic class Solution {
/*
* @param nums: an array with positive and negative numbers
* @param k: an integer
* @return: the maximum average
*/
public double maxAverage(int[] nums, int k) {
// write your code here
double max=nums[0],min=nums[0];
for(int x: nums){
if(x>max){
max=x;
}
if(x<min){
min=x;
}
}
double avg=0.0;
while(max-min>1e-6){
boolean flag=false;
avg=min+(max-min)/2.0;
double[] d =new double[nums.length+1];
d[0]=0.0;//数组d中d[0]存0,d[1]存nums中第1个数与avg的差...
double preMin=d[0];
for(int i=1;i<=nums.length;i++){
d[i]=d[i-1]+nums[i-1]-avg;
if(i>=k && d[i]-preMin>=0){
flag=true;
break;
}
if(i>=k){
preMin=Math.min(preMin,d[i-k+1]);
}
}
if(flag){
min=avg;
}
else{
max=avg;
}
}
return min;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: