1. 程式人生 > >最大平均值子陣列-LintCode

最大平均值子陣列-LintCode

給出一個整數陣列,有正有負。找到這樣一個子陣列,他的長度大於等於 k,且平均值最大。

注意事項:
保證陣列的大小 >= k

樣例:
給出 nums = [1, 12, -5, -6, 50, 3], k = 3
返回 15.667 // (-6 + 50 + 3) / 3 = 15.667

一刷,超時。

#ifndef C617_H
#define C671_H
#include<vector>
#include<iostream>
using namespace std;
class Solution {
public:
    /*
    * @param nums: an array with positive and negative numbers
    * @param k: an integer
    * @return: the maximum average
    */
double maxAverage(vector<int> &nums, int k) { // write your code here int len = nums.size(); vector<double> sum(len+1, 0); sum[0] = 0; for (int i = 1; i <= len; ++i) { sum[i] = sum[i - 1] + nums[i-1]; } int
m = len; double res = -DBL_MAX; while (m >= k) { double target = -DBL_MAX; for (int i = 0; i < len; ++i) { if (i + m <= len) target = maxVal(target, sum[i + m] - sum[i]); else break
; } res = maxVal(res, target / m); --m; } return res; } template<typename T> T maxVal(T a, T b) { return a > b ? a : b; } }; #endif

九章答案程式碼
C++程式碼
思路:二分法

  • 首先找到陣列的最大值與最小值,確定平均值的範圍;
  • 不斷縮小範圍,在r-l的值足夠小的時候,得到結果
    令mid=(r+l)/2,將原陣列的每個元素減去mid,如果可以找到至少k個相鄰元素的和>0,說明最終結果一定比現在的mid要大,在[l,mid]範圍內尋找,否則,在[mid,r]範圍內尋找。
  • 接下來判斷是否存在有至少k個相鄰元素的>0,利用陣列sum[i]儲存sum[i]-mid到sum[i-1]-mid的和,當i>k時,用一個min_pre的變數來儲存sum[0]~sum[i-k]之間的最小值,並且每次隨著i變大不斷更新該數字。這樣sum[i]-min_pre得到的是sum[k+1]~sum[i-1],它所記錄的總和個數也就是到num[i]為止能夠找到的最大平均值子陣列的長度。

參考後代碼

#ifndef C617_H
#define C671_H
#include<vector>
#include<iostream>
using namespace std;
class Solution {
public:
    /*
    * @param nums: an array with positive and negative numbers
    * @param k: an integer
    * @return: the maximum average
    */
    double maxAverage(vector<int> &nums, int k) {
        // write your code here
        double l = INT_MAX, r = INT_MIN;
        int len = nums.size();
        for (auto c : nums)
        {
            if (c < l)
                l = c;
            if (c>r)
                r = c;
        }
        vector<double> sum(len+1, 0);
        sum[0] = 0;
        while (r - l >= 1e-6)
        {
            double mid = (l + r) / 2.0;
            double min_pre = 0;
            bool check = false;
            for (int i = 1; i <= len; ++i)
            {
                sum[i] = sum[i - 1] + nums[i - 1] - mid;
                if (i >= k&&sum[i] - min_pre >= 0)
                {
                    check = true;
                    break;
                }
                if (i >= k)
                    min_pre = minVal(min_pre, sum[i - k + 1]);
            }
            if (check)
                l = mid;
            else
                r = mid;
        }
        return l;
    }
    double minVal(double a, double b)
    {
        return a < b ? a : b;
    }
};
#endif