n個人從m個啤酒龍頭接啤酒,需要多久接完?

題目

酒館里酒館里有m個龍頭可供顧客們接啤酒,每個龍頭每秒的出酒量相等,都是1?,F(xiàn)有n名顧客準(zhǔn)備接酒,他們初始的接酒順序已經(jīng)確定。將這些顧客按接酒順序從1到n編號,i號顧客的接酒量為w[i]。接酒開始時,1到m號顧客各占一個酒龍頭,并同時打開龍頭接酒。當(dāng)其中某個顧客j完成其接酒量要求w[j]后,下一名排隊等候接酒的顧客k馬上接替j顧客的位置開始接酒。這個換人的過程是瞬間完成的,且沒有任何酒的浪費(fèi)。即j顧客第x秒結(jié)束時完成接酒,則k顧客第x+1秒立刻開始接酒。若當(dāng)前接酒人數(shù)n不足m,則只有n個龍頭供酒,其它m-n個龍頭關(guān)閉。 現(xiàn)在給出n名顧客的接酒量,按照上述規(guī)則,問所有顧客都接完酒需要多少秒?

題目分析

對于這道題目,因為有n個顧客接酒,因此我們至少需遍歷整個輸入數(shù)組一次,則算法的時間復(fù)雜度不可能低于O(n)??紤]到總計有m個水龍頭,因此同時可以有m個人接酒。而結(jié)束最早的總當(dāng)前正在接酒的用戶中所需酒量最少的人。也就是說我們每次都需要找到結(jié)束時間最早的人。那么使用最小堆就能夠非常方便地實現(xiàn)這一目的。使用最小堆保存當(dāng)前正在接酒的用戶的結(jié)束時間,我們就可以在O(1)時間內(nèi)決定當(dāng)前m個正在接酒的人中哪一個最先結(jié)束。同時最小堆重新heapify的時間為O(logm)。我們只要重復(fù)這一過程,在最小堆的大小小于m的時候不斷向其中添加用戶的結(jié)束時間,然后取出結(jié)束時間最早的用戶,得到其結(jié)束時間作為當(dāng)前時間,并在當(dāng)前時間的基礎(chǔ)上加上排隊的用戶中下一個需要接酒的時間并放入堆中,則最后一個從堆中被取出的時間為所有用戶接酒所需的時間。

時空復(fù)雜度

使用了一個大小為m的最小堆保存正在接酒的用戶。因此空間復(fù)雜度為O(m)

遍歷了一遍所有用戶,此為O(n),同時每個用戶都被放入堆中及從堆中取出一次,取出為O(1),取出后堆重新heapify為O(logm),放入為O(logm),因此時間復(fù)雜度為O(nlogm)。

算法實現(xiàn)如下

public class GetBeerForAll {
    public static int getBeer(int[] clients, int beerTap) {
        // Deal with invalid inputs
        if (clients == null || clients.length == 0 || beerTap == 0) {
            return -1;
        }
        
        PriorityQueue<Integer> currClients = new PriorityQueue<>();
        int index = 0; // the index of the next clients that will use the beer tap
        int currTime = 0; // current time.
        while (index < clients.length || !currClients.isEmpty()) {
            // As long as the number of clients that is using beer tap right now is less
            // than the total number of beer tap and there is more clients in line, 
            // we can put more clients into the PriorityQueue
            // that contains the clients currently served by beer tap.
            while(currClients.size() < beerTap && index < clients.length) {
                currClients.add(clients[index++] + currTime);
            }
            
            // Otherwise, all clients is either already been served or is currently being served,
            // constantly poll out the clients that finished the earliest and renew the current time
            // until all clients finished. 
            // At this time, current time is the time that all clients have been served.
            currTime = currClients.poll();
        }
        
        return currTime;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • sì 支zhī茶chá 對duì 酒jiǔ,賦fù 對duì 詩shī,燕yàn子zi 對duì 鶯yīng 兒é...
    每個人的孟母堂閱讀 1,451評論 0 6
  • *以下內(nèi)容來自YC的掌門人Sam Altman的博客,原文鏈接見文章尾部。 所有偉大的公司都有,且僅有一個共同點:...
    蘇少爺閱讀 567評論 0 0
  • 前些天在微博上看見有人在推薦一部臺灣電視劇《荼靡》,自大學(xué)期間看過《我可能不會愛你》就再也沒看過電視劇的...
    大寫的蘇子閱讀 595評論 0 0
  • 唯有羊城的冬天才會這么風(fēng)情萬種吧,不冷,也不熱,下午五點的陽光微醺醺的有點懶散,路面的車輛在它的懷抱里急急匆匆的,...
    f1cbcae5f0a8閱讀 270評論 0 0

友情鏈接更多精彩內(nèi)容