表現(xiàn)良好的最長時間段 前綴和+單調棧

給你一份工作時間表 hours,上面記錄著某一位員工每天的工作小時數(shù)。
我們認為當員工一天中的工作小時數(shù)大于 8 小時的時候,那么這一天就是「勞累的一天」
所謂「表現(xiàn)良好的時間段」,意味在這段時間內,「勞累的天數(shù)」是嚴格 大于「不勞累的天數(shù)」
請你返回「表現(xiàn)良好時間段」的最大長度。

示例 1:
輸入:hours = [9, 9, 6, 0, 6, 6, 9]
輸出:3
解釋:最長的表現(xiàn)良好時間段是 [9,9,6]。

這個思路是看的解題思路里面一個Python3大佬的答案寫的。
https://leetcode-cn.com/problems/longest-well-performing-interval/solution/
大佬就是大佬,即使給出了思路,我還是看了好久好久才看懂,期間還去補習了單調棧前綴和的知識才看懂思路。
不了解或者不夠熟悉推薦再去補一下相關知識:
單調棧和應用實踐
前綴和
首先根據(jù)時間是否大于8,量化成1和-1利與計算, [9, 9, 6, 0, 6, 6, 9] => [1, 1, -1, -1, -1, -1, 1],所以hours當前是[1, 1, -1, -1, -1, -1, 1]。
這個操作比較好理解,其實理解題意,我們要做的就是得到一個區(qū)間,這個區(qū)間里1和-1加起來要大于0。怎么方便的得到一個區(qū)間的和?很明顯,這就是前綴和存在的意義。
轉化成前綴和prefixSrc = [0, 1, 2, 1, 0, -1, -2, -1],我們在前綴和前面加了一個0,是為了好操作。那如何得到一個區(qū)間呢?如果要得到[1,3]區(qū)間,根據(jù)前綴和定義需要用prefixSrc[3]-prefixSrc[1],所以我們需要得到數(shù)組中所有prefixSrc[b]-prefixSrc[a] > 0的[a,b]區(qū)間,就是我們需要的結果。


上圖所示,我們需要的就是那兩段紅色線段。我們選擇從后往前遍歷,

如何得到第二段紅色線段呢?

index=7,prefixSrc[7]=-1;需要找到左邊第一個比自己小的數(shù)字。這段描述熟悉不?到了單調棧登場的時候了。
我們對prefixSrc = [0, 1, 2, 1, 0, -1, -2, -1]生成單調棧,stack=[0,5,6],對應[0, -1, -2],如果當前元素大于棧頂元素,棧頂元素出棧,因為-1 > -2,所以6出棧,計算寬度width=7-6=1

如何得到第一段紅色線段呢?

其實因為我們便利到index=3的時候prefixSrc[3]的時候發(fā)現(xiàn)prefixSrc[3]大于0,此時棧內只剩一個0,所以寬度width=3-0=3
因為0永遠在第0位所以只要出現(xiàn)大于0的情況,0~n就是表現(xiàn)良好時間段成立的。
我們繼續(xù)舉個例子:

OA段跟BCD段都是我們需要的,而AB段則不是。想明白這個就明白了。

  1. DCB:從D往C遍歷的過程中我們會不斷把單調棧里面的index彈出去,直到B,得到DCB的寬度。
  2. AO:到A后發(fā)現(xiàn)大于零,彈出棧底的0,得到OA的寬度

代碼實現(xiàn):

     /**
     * 使用前綴和+單調棧
     *
     * @param src 源數(shù)組
     */
    public int longestWPI(int[] hours) {
        int max = 0;
        Stack<Integer> stack = new Stack<>();
        int[] prefixSrc = new int[hours.length + 1];
        //大于8的置為1,否則置為-1
        for (int i = 0; i < hours.length; i++) {
            if (hours[i] > 8) {
                max = 1;
                hours[i] = 1;
            } else {
                hours[i] = -1;
            }
            //初始化前綴和數(shù)組
            prefixSrc[0] = 0;
            prefixSrc[i + 1] = prefixSrc[i] + hours[i];
        }
        for (int i = 0; i < prefixSrc.length - 1; i++) {
            //實現(xiàn)單調棧
            if (stack.isEmpty()) {
                stack.push(i);
            } else {
                if (prefixSrc[i] < prefixSrc[stack.peek()]) {
                    stack.push(i);
                }
            }
        }
        //開始尋找,從后往前遍歷
        for (int i = prefixSrc.length - 1; i >= 0; i--) {
            int last = i;
            while (!stack.isEmpty() && prefixSrc[i] > prefixSrc[stack.peek()]) {
                last = stack.pop();
            }
            if (last != i) {
                int width = i - last;
                max = max > width ? max : width;
            }
        }
        return max;
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容