给你一份工作时间表 hours
,上面记录着某一位员工每天的工作小时数。
我们认为当员工一天中的工作小时数大于 8
小时的时候,那么这一天就是「劳累的一天」。
所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。
请你返回「表现良好时间段」的最大长度。
示例 1:
```txt
输入:hours = [9,9,6,0,6,6,9]
输出:3
解释:最长的表现良好时间段是 [9,9,6]。
```
示例 2:
```txt
输入:hours = [6,6,6]
输出:0
```
提示:
1 <= hours.length <= 10^4
0 <= hours[i] <= 16
表现良好的最长时间段
题目
给你一份工作时间表 hours
,上面记录着某一位员工每天的工作小时数。
我们认为当员工一天中的工作小时数大于 8
小时的时候,那么这一天就是「劳累的一天」。
所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。
请你返回「表现良好时间段」的最大长度。
示例 1:
1 | 输入:hours = [9,9,6,0,6,6,9] |
示例 2:
1 | 输入:hours = [6,6,6] |
提示:
-
1 <= hours.length <= 10^4
0 <= hours[i] <= 16
题解
方法一:
思路
我们将hours
二值化。对于hours[i]>8
则hours[i] = 1
,否则hours[i] = -1
。
对于「表现良好的时间段」,其实就是区间和至少为1。
为了快速得到区间和,可以用前缀数组。
设p[i]
为前i个数的最大值。即p[0] = 0, p[i] = p[i-1] + hours[i-1]
此时对于任意p[j]-p[i]>=1
的区间[i,j]
,都是「表现良好的时间段」。
如果我们固定右端点j,枚举左端点i,则可以在O(n^2)时间复杂度找到答案。
又没有快速找到最优的左端点的方法呢?
显然对于右端点j,最优的左端点应该是满足p[i] < p[j]
最小的i。
可以用树状数组加快查询,不过p[i]
存在非正数,需要离散化。
将离散化的前缀和作为树状数组的下标,前缀数组的下标作为树状数组的值,维护最小值。即可。
代码
1 | class Solution { |
方法二:
思路
巧妙的单调栈。
考虑哪些可以作为区间左端点,若i可以作为左端点,那么作为左端点的j(j < i),满足p[j]>p[i]
。
若p[j]<p[i]
,后续的右端点可以选择j,这样宽度更大。
因此可以作为左端点的值单调递减,我们将其存入栈中,设栈顶元素为top.
然后从右向左遍历寻找右端点。对于遍历的j,若p[j] > p[top]
,更新答案,并移除栈顶。
j之前的元素i即便p[i]>p[top]
,由于j靠后,i更新的答案也不如j优,故可以直接删除栈顶。
代码
1 | class Solution { |