最大平均值子數組
給出一個整數數組,有正有負。找到這樣一個子數組,他的長度大於等於 k
,且平均值最大。
注意事項
保證數組的大小 >= k
給出 nums = [1, 12, -5, -6, 50,
3]
, k = 3
返回 15.667
// (-6 + 50
+ 3) / 3 = 15.667
這道題可以用二分法去做。總結:所有有最大最小值去求某個值的題目,都可以用二分法。具體代碼和解釋見代碼:
public double maxAverage(int[] nums, int k) {
double high = Integer.MIN_VALUE;
double low = Integer.MAX_VALUE;
for (int n : nums) {
if (high < n) {
high = n;
}
if (low > n) {
low = n;
}
}
// 1. 最大平均子數組的平均數一定小於數組最大值,大於數組最小值,用這個最大最小去逼近
while (high - low > 1e-6) {
double mid = (high + low) / 2;
if (hasBiggerSubArray(nums, k, mid)) {
low = mid;
} else {
high = mid;
}
}
return high;
}
private boolean hasBiggerSubArray(int[] nums, int k, double mid) {
double[] sum = new double[nums.length];
double min = 0;
sum[0] = nums[0] - mid;
for (int i = 1; i < nums.length; i++) {
sum[i] = sum[i - 1] + nums[i] - mid;
if (i >= k - 1 && sum[i] > min) {//
return true;
}
if (i >= k - 1) {
// 2.求i前面且距離i大於等於長度k的某個偏差最小值。
// 2.1爲啥找前面最小偏差呢:假定這個值爲nums[j],如果這個最小偏差被後面某個偏差加大了,說明j到i這個子數組裏面存在平均數比
// mid大的,只有i到j的平均數比mid大才會使得sum[i] > sum[j](如果比mid小,sum只會越加越小);這步是這個算法的重難點
// 2.2爲啥長度要大於k才執行此邏輯:確保2.1中說的加大了偏差的子數組的長度大於等於k
min = Math.min(min, sum[i - k + 1]);
}
}
return false;
}