Given an array with positive and negative numbers, find the
maximum average subarray
which length should be greater or equal to given length k
.Example
Example 1:
Input:
[1,12,-5,-6,50,3]
3
Output:
15.667
Explanation:
(-6 + 50 + 3) / 3 = 15.667
Example 2:
Input:
[5]
1
Output:
5.000
Notice
It's guaranteed that the size of the array is greater or equal to k.
Analysis:Binary search for the result. Given a target average T, can we find out
A[left] + ... A[right] / (right - left + 1) >= T. If we can find out this T, meaning the T we tried might be too small. We should try a bigger T.
For A[left] + ... A[right] / (right - left + 1) >= T, we can transform to
(A[left] - T) + ... + (A[right] - T) >= 0
That is, For B[i] = A[i - 1], can we find out B[i] + ... + B[j] >= 0? This can be done by prefix sum.
Code (Java):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | 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) { if (nums == null || nums.length == 0 || k <= 0 || k > nums.length) { return 0 ; } double lo = nums[ 0 ]; double hi = nums[ 0 ]; for ( int i = 0 ; i < nums.length; i++) { lo = Math.min(lo, nums[i]); hi = Math.max(hi, nums[i]); } while (lo + 1e- 5 < hi) { double mid = lo + (hi - lo) / 2 ; if (canFind(nums, k, mid)) { lo = mid; } else { hi = mid; } } return lo; } private boolean canFind( int [] nums, int k, double target) { double leftSum = 0 ; double rightSum = 0 ; double minLeftSum = 0 ; for ( int i = 1 ; i <= nums.length; i++) { rightSum += nums[i - 1 ] - target; if (i >= k) { leftSum += i > k ? nums[i - k - 1 ] - target : 0 ; minLeftSum = Math.min(leftSum, minLeftSum); if (rightSum - minLeftSum >= 0 ) { return true ; } } } return false ; } } |
No comments:
Post a Comment