lintcode(617)最大平均值子陣列
阿新 • • 發佈:2019-01-01
描述;
給出一個整數陣列,有正有負。找到這樣一個子陣列,他的長度大於等於 k
,且平均值最大。
樣例:
給出 nums = [1, 12, -5, -6, 50, 3]
, k = 3
返回 15.667
// (-6 + 50 + 3) / 3 = 15.667
思路:
平均值範圍在最大值和最小值之間,採用二分法來解決,逐漸縮小最大平均值的範圍。之前試過遍歷每一種情況,超時了。
在程式碼後面做了一下具體的解釋,希望我講清楚了。
public 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 high = Integer.MIN_VALUE; double low = Integer.MAX_VALUE; for(int i = 0;i<nums.length;i++){ if(nums[i] > high){ high = nums[i]; } if(nums[i] < low){ low = nums[i]; } } while(high - low >= 1e-6){ double mid = (high + low)/2.0; if(search(nums , k ,mid)){ low = mid; }else{ high = mid; } } return high; } public boolean search(int[] nums , int k , double mid){ double min = 0; double[] sum = new double[nums.length + 1]; sum[0] = 0; for(int i = 1;i<=nums.length;i++){ sum[i] = sum[i - 1] + nums[i - 1] - mid; if(i>=k && sum[i] >= min){ return true; } if(i>=k){ min = Math.min(min , sum[i - k + 1]); } } return false; } }
1.一組數的平均值一定在這組數中的最大值和最小值之間。
min<=average<=max;
這組數的子陣列的平均值也一定在這個範圍內。
2.利用這一性質,首先求解最大值和最小值並求出它們的平均數mid。
3.用search函式判斷至少k個長度的子陣列的平均值與mid的大小。
search函式中計算了每一個值與mid的差,也就是和平均數之間的偏差,並依次累加求和,存貯在sum[]中。
然後比較偏差的變化,在子陣列長度大於等於k之後,開始比較當前偏差之和與k個元素之前的所有偏差的最小值(以後簡稱最小值),如果當前偏差之和大於最小值,說明子陣列的平均數被增大了,也就說明存在某一子陣列的平均值大於mid,所以返回true,這樣low=mid;如果遍歷到最後發現偏差的和始終小於最小值,說明所有子陣列的平均值,都小於mid,所以返回false,這樣high=mid。
上述子陣列的長度均要求大於等於k,不再強調。
所以類似於二分法,不斷地確定子陣列最大平均數的範圍,直至high=low。