Leetcode 644. Maximum Average Subarray II 最大平均区间2 解题报告

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/MebiuW/article/details/76222743

这道题目呢,和之前的643类型差不多,但是更难。
首先这道题我看了Solution的解法,反正不是n2的复杂度,是 n*log(max-min) 的样子吧,一开始怎么做都不对,超时。。。直到直接跑了solution的代码(java),发现原因不是代码写错了,而是python特别慢!!!! 所以不是大神就别用python了,所以我大概还是以Java为主吧。

Given an array consisting of n integers, find the contiguous subarray whose length is greater than or equal to k that has the maximum average value. And you need to output the maximum average value.

Example 1:
Input: [1,12,-5,-6,50,3], k = 4
Output: 12.75
Explanation:
when length is 5, maximum average value is 10.8,
when length is 6, maximum average value is 9.16667.
Thus return 12.75.
Note:
1 <= k <= n <= 10,000.
Elements of the given array will be in range [-10,000, 10,000].
The answer with the calculation error less than 10-5 will be accepted.

解法上最简单的是暴力,但是很明显不通过,不可可能的,就不说了

这道题的思想就是二分猜测,首先需要预测的这个平均值肯定是介于最大值和最小值之间的,所以就以二分法的思想,不停的猜测就可以了,这个就是核心思想,进行二分法的需要操作log(max-min)次。

我们不停的猜测那个mid值(max和min的平均值)在给定的序列中能否满足,也就是说是否存在一个大于等于k的区间的平均值大于等于mid值,如果是,我们就可以把下限值min变成mid,反之改变max,就这样做,直到猜测范围小于0.00001就可以直接给出答案了(题目说了有误差的容许范围,小提示吧)。

另外一个难点在于如何在线性的时间内,判别nums当中是否存在这样的一段,使得平均值大于等于mid。做法也很简单:
顺序遍历数组nums(这里需要统一减去mid),统计两个值这里第一个值是sums,从位置0到当前位置j的和。另外一个是从0到某个位置i的和的最小值min_sum(其中i小于j,且i和j的长度大于等于k)。也就是等价于找一段和大于0的子区间,注意不是找最大,所以不用太严格。。

public class Solution {
    public double findMaxAverage(int[] nums, int k) {
        double max = Double.MIN_VALUE;
        double min = Double.MAX_VALUE;

        // 寻找最值
        for (int n: nums) {
            max = Math.max(max, n);
            min = Math.min(min, n);
        }

        double last_mid = max, error = Integer.MAX_VALUE;
        while (max-min > 0.00001) {
            double mid = (max + min) / 2.0;
            if (check(nums, mid, k))
                min = mid;
            else
                max = mid;
            error = Math.abs(last_mid - mid);
            last_mid = mid;
        }
        return min;   
    }


    // 判断这个区间里面,是否有一段大于等于K的长度的最长序列,满足要求,就是最大的累计和,减去最小的累积和
    public boolean check(int[] nums, double mid, int k) {
        double sum = 0, prev = 0, min_sum = 0;
        for (int i = 0; i < k; i++)
            sum += nums[i] - mid;
        if (sum >= 0)
            return true;
        for (int i = k; i < nums.length; i++) {
            sum += nums[i] - mid;
            prev += nums[i - k] - mid;
            min_sum = Math.min(prev, min_sum);
            if (sum >= min_sum)
                return true;
        }
        return false;
    }
}

猜你喜欢

转载自blog.csdn.net/MebiuW/article/details/76222743