一日一练: 表现良好的最长时间段

118 阅读1分钟

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

解题思路:

  • hours中大于8小时的天映射成1,等于小于的8映射成-1,以[9,9,6,0,6,6,9]为例,得到数组[1, 1, -1, -1, -1, -1, 1]
  • 题目要求劳累的天数大于不劳累的天数,即1的个数大于-1的个数。这里可以通过前缀和解决,先得到前缀和preSum[0, 1, 2, 1, 0, -1, -2, -1],然后题目可以转成:求preSum中索引 i 和 j,使 j - i 最大,且保证 presum[j] - presum[i] 大于0
  • 用单调递减栈维护preSum的较小值的索引[0, 5, 6]
  • preSum从后往前遍历,将每个元素与单调栈顶的元素进行对比,如果比栈顶元素小,更新结果长度为当前索引 - 栈顶索引,并取最大值

代码:

function longestWPI(hours) {
  const Len = hours.length
  const score = []
  let ans = 0
  for(let i = 0; i < Len; i++) {
      if (hours[i] > 8) {
          score[i] = 1
      } else {
          score[i] = -1
      }
  }
  let preSum = [0]
  let sum = 0
  for(let i = 0; i < Len; i++) {
      sum += score[i]
      preSum.push(sum)
  }
  const stack = []
  for(let i = 0; i < Len; i++) {
      if(!stack.length || preSum[stack[stack.length - 1]] > preSum[i]) {
          stack.push(i)
      }
  }
  let k = Len
  while(k >= 0) {
      while(stack.length && preSum[stack[stack.length - 1]] < preSum[k]) {
          ans = Math.max(ans, k - stack[stack.length - 1])
          stack.pop()
      }
      k--
  }

  return ans
};

参考资料: