【路飞】算法-表现良好的时间段

245 阅读2分钟

题目链接 leetcode-cn.com/problems/lo…

题目简介 给你一份工作时间表hours,上面记录着某一位员工每天的工作小时数。
我们认为当员工一天中的工作小时数大于8小时的时候,那么这一天就是【劳累的一天】。
所谓【表现良好的时间段】,意味着这段时间内,【劳累的天数】是严格 大于【不劳累的天数】。
请你返回【表现良好的时间段】的最大长度

示例

输入: hours = [9,9,6,0,6,6,9]
输出: 3
解释: 最长的表现良好时间段是 [9,9,6]

解题思路 使用前缀+单调栈的方法。
1、前缀:已输入样例hours为例,将大于8的记为1,小于等于8的记为**-1**,得到source数组
2、对source数组计算前缀和 presum = 【0,1,2,1,0,-1,-2,-1】
3、题目要求返回表现良好的最大长度,就是求得分1的个数大于-1的个数的最长的一段。
4、维护一个栈stack,存储presum中的元素索引,栈中索引指向的元素严格单调递减,比如presum中严格单调递减的元素是 0, -1, -2;所以stack= [0, 5, 6];
5、从后往前遍历presum数组,与栈顶索引指向元素比较,如果相减结果大于0,则一直出栈,直到不大0为止,然后更新当前最大宽度

代码实现

/**
 * @param {number[]} hours
 * @return {number}
 */
 var longestWPI = function(hours) {
         // 记录 hours 的长度
         const n = hours.length;
         // 创建source数组,长度和hours一致
         const source = new Array(n).fill(0);
         // 像source数组中记录当前得分
         for(let i=0;i<n;i++){
             if(hours[i] > 8) {
                 source[i] = 1;
             }
             else {
                 source[i] = -1;
             }
         }
         // 创建 presum数组.
         const presum = new Array(n + 1).fill(0);
             // 计算前缀和
         for (let i = 1; i < n + 1; i++){
          presum[i] = presum[i - 1] + source[i - 1];
        }
        // 定义长度
        let max = 0;
        const stack = [];
            // 向栈中添加递减元素额度下标
        for (let i = 0; i < n + 1; i++){
          if (!stack.length || presum[stack[stack.length-1]] > presum[i]) {
            stack.push(i);
          }
        }
        let i = n;
        while (i > ans) {
          while (stack.length && presum[stack[stack.length-1]] < presum[i]) {
            ans = Math.max(ans, i - stack.pop());
          }
          i -= 1
        }
        return ans;
 }