最大平均值子數組

題目描述

給定n個數的數組,找到所有長度大于等于k的連續(xù)子數組中平均值最大的那個。返回那個最大的平均值粥鞋。

1 <= k <= n <= 10000,數組中的元素在范圍[-10000, 10000]之間壕曼,最后返回的答案的誤差應在10^(-5)以內等浊。

輸入樣例
輸入: [1,12,-5,-6,50,3], k = 4
輸出: 12.75

說明:
長度為4的子數組中,最大的平均值為12.75筹燕,(=(12 + -5 + -6 + 50)/4)

長度為5的子數組中,最大的平均值為10.8踪少,(=(12 + -5 + -6 + 50 + 3)/5)

長度為6的子數組中糠涛,最大的平均值為9.16667。(所有數的平均值)

因此返回12.75集漾。

解題思路

暴力枚舉

枚舉所有的長度大于等于k的子數組計算平均值砸脊,并從得到的平均值中求最大值,這樣可以做到時間復雜度O(n^2)凌埂,但是會超時。

二分法

有些最值問題可以轉化為判斷問題從而用二分法求得答案.
本題可以利用二分求解牲平。 即
對于n個數a(0),a(1),……,a(n-1)振峻,以及一個數A大诸,如果存在一個子數組起始于i钧敞,長為L>=k胳蛮,使得其平均值大于等于A,即(a(i)+a(i+1)+……+a(i+L-1))/L >= A斗幼,那么我們所求的答案應當大于等于A茂洒;反之如果對于所有長度大于等于k的子數組,其平均值均小于A督勺,那么我們所求的答案也必然小于A。

二分法的初始區(qū)間:
[min{a(i)},i=0~n-1 , max{a(i)},i=0~n-1]
因為在一組數中次询,該組數的平均值不會小于這組數的最小值瓷叫,也不會大于這組數的最大值。同時摹菠,該組數的連續(xù)子數組的平均值 位于 這組數的最小值和最大值之間。

判斷是否存在長度至少為k的子數組蔽介,其平均值大于等于A
式子(a(i)+a(i+1)+……+a(i+L-1))/L >= A煮寡,其等價于(a(i)-A)+(a(i+1)-A)+……+(a(i+L-1)-A)>=0,令b(0)=a(0)-A , b(1)=a(1)-A , …… , b(n-1)=a(n-1)-A薇组,那么判斷a數組中是否存在長度至少為k的子數組平均值大于等于A坐儿,等價于判斷b數組中是否存在長度至少為k的子數組和大于等于0宋光,只要求出b數組長度至少為k的子數組的最大和與0比較即可.

求長度大于等于k的最大和子數組:
求長度大于等于k的最大和子數組比原問題容易的多炭菌,令s為b的前綴和子數組,即s(i)=b(0)+b(1)+……+b(i-1)娃兽,且s(0)=0尽楔,那么b(j)到b(i-1)的區(qū)間和可表示為s(i)-s(j),找長度大于等于k的最大和子數組等價于找i,j玛荞,滿足i-j>=k呕寝,且使s(i)-s(j)最大。

固定i下梢,則要使s(i)-s(j)最大,s(j)應最小讶坯,同時也應滿足j<=i-k岗屏,令p(i) = min{s(j)},j<=i-k,故 固定 i 時s(i)-s(j)的最大值為s(i)-p(i)这刷,枚舉所有i即可得到最終的最大值。因為s(i),p(i)均可通過遞推得到似袁,故時間復雜度為O(n)率碾。

綜上:總的時間復雜度: O(n * log(maxVal-minVal) / eps)

代碼如下:

public double findMaxAvg(int[] A, int k){
        double left = Integer.MAX_VALUE;
        double right = Integer.MIN_VALUE;

        // 初始化 二分區(qū)間
        for(int i=0; i<A.length; ++i){
            left = Math.min(left, (double)A[i]);
            right = Math.max(right, (double)A[i]);
        }


        while(right-left > 1e-6){
            // 求出當前區(qū)間的中值
            double mid = (right-left)/2;

            // 求數組的累加和
            double[] sumAi = new double[A.length+1];
            sumAi[0] = 0;
            for(int i=0; i<A.length; i++){
                sumAi[i+1] = sumAi[i] + A[i] - mid;
            }

            // 求長度大于等于k的最大和子數組
            // 找長度大于等于k的最大和子數組等價于找i,j,滿足i-j>=k绒尊,且使s(i)-s(j)最大
            // 最大化s(i),最小化s(j)
            double preMin = 0;
            double sumMax = Integer.MIN_VALUE;
            for(int i=k; i<=A.length; ++i){
                sumMax = Math.max(sumMax, sumAi[i] - preMin);
                preMin = Math.min(preMin, sumAi[i-k+1]);
            }

            // 判斷是否存在長度大于等于k的字數組仔粥,其平均值大于等于 mid(sumMax>0)
            if(sumMax>0)
                left = mid;
            else right = mid;

        }
        return left;
    }

該算法的思路和實現基本參考了九章算法的題解蟹但。

斜率優(yōu)化+單調隊列解法

數列a中第 i 個位置到 第 j 個位置的平均值:avg(i, j) = (ai, ..., a) / (j-i+1).

若令sum(i) 表示數列a中從第 1 個位置 到 第 i 個位置 的累加和谭羔,則
avg(i, j) = (sum(j) - sum(i)) / (j - i + 1).

avg(i, j) 現在表示為 sum(.) 的斜率。

根據題意客叉,我們的目標是找出子數組長度大于等于k话告,且求出子數組的最大平均值,即關于sum(.)的斜率最大的子數組沙郭。

假設我們已經得到 sum 數組。
由于數組的遍歷吓著,一般從左邊開始, 因此我們假設 k < j < i. (i為要加入的點)
如果avg (k, j) > avg(j, i)送挑,表明 i 點 不應該被加入到解集中
,因為只有維護一個下凸的集合惕耕,我們才可以找到最大的斜率,如圖1所示对扶,只有我們維護了下凸集合惭缰,紅色箭頭會越來越陡峭,即斜率越來越大漱受。

圖1

由于屏蔽掉了要加入的點昂羡,相當于縮小了搜索空間。

在新加入點 i 后虐先,如果 avg(y, x) < avg(x, i), 顯然avg(y, i) < avg(x, i), y已經沒有必要存在,因此可以從解集中去掉撰洗。

圖2

由于知道解集中的元素是單調遞增的,我們可以使用單調隊列保存解集差导。

// TODO code

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末设褐,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子助析,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件锥惋,死亡現場離奇詭異开伏,居然都是意外死亡,警方通過查閱死者的電腦和手機固灵,發(fā)現死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門巫玻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人仍秤,你說我怎么就攤上這事』烁。” “怎么了苇本?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長瓣窄。 經常有香客問我,道長递递,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任贰逾,我火速辦了婚禮菠秒,結果婚禮上,老公的妹妹穿的比我還像新娘践叠。我一直安慰自己,他們只是感情好管挟,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布弄捕。 她就那樣靜靜地躺著,像睡著了一般守谓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荞雏,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天平酿,我揣著相機與錄音,去河邊找鬼别洪。 笑死柳刮,一個胖子當著我的面吹牛挖垛,可吹牛的內容都是我干的秉颗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼哪替,長吁一口氣:“原來是場噩夢啊……” “哼菇怀!你這毒婦竟也來了晌块?” 一聲冷哼從身側響起帅霜,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钝尸,沒想到半個月后搂根,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡猪叙,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年仁卷,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片五督。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡充包,死狀恐怖遥椿,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情冠场,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布钢悲,位于F島的核電站舔株,受9級特大地震影響,放射性物質發(fā)生泄漏载慈。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一辞做、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秤茅,春花似錦、人聲如沸孔厉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拼余。三九已至,卻和暖如春凡橱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稼钩。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工达罗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粮揉。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓扶认,卻偏偏與公主長得像,于是被迫代替她去往敵國和親辐宾。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內容