题目介绍
给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。
我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」。
所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。
请你返回「表现良好时间段」的最大长度。
示例1
输入: hours = [9,9,6,0,6,6,9]
输出: 3
解释: 最长的表现良好时间段是 [9,9,6]。
示例2
输入: hours = [6,6,6]
输出: 0
提示:
1 <= hours.length <= 10^40 <= hours[i] <= 16leetcode-1124 表现良好的最长时间段
b站视频
解题思路
本题的解题关键在于找出每一项之前 表现良好的最长时间段,然后取出这些 表现良好的最长时间段 中最大的那个
我们拿 [9,9,6,0,6,6,9] 进行说明,首先将每一项根据 大于等于8小时(以下简称“大8”)记为 1,小于8小时(以下简称“小8”)记为 -1,可以得到一个新的数组
假设初始值为0,将新数组的每一项的前
n项和相加,所得到的数组的每一项表示的意思是当前项大8比小8多的天数
要找到当前项之前 表现良好的最长时间段,需要将当前项的下标减去 sum 值小于当前项并且离当前项最远的位置下标
假如要找到 sum 值为 1 的 表现良好的最长时间段,需要先找到当前项之前有没有 sum 值为 0 的项,如果找到了,再往前找有没有 sum 值为 -1 的项…… 一直找到找不到为止,那么当前下标与 sum 为 1 的下标之间的差值即为 表现良好的最长时间段
这里可以得出一个有用的结论 sum 为 1 的 表现良好的最长时间段 = sum 为 0 的 表现良好的最长时间段 + sum 为 1 的位置下标 - sum 为 0 的位置下标
依次对 sum 的每一项进行上述计算,然后找出其中最大的值即为最终的结果
解题代码
var longestWPI = function(hours) {
// cnt用于标记大于8小时与不大于8小时天数之差,max用于保存当前“表现良好的时间段”
let cnt = 0, max = 0
// ind用于存放第一次出现cnt的值的位置,sum用于存放第一次出现cnt时的前缀和
// 假设初始时cnt为0,位置为-1,前缀和为0
const ind = new Map([[0, -1]]), sum = new Map([[0, 0]])
for (let i = 0; i < hours.length; i++) {
// 大于8小时,cnt++,否则cnt--
hours[i] > 8 ? cnt++ : cnt--
// 如果前面没有出现过cnt
if(!ind.has(cnt)) {
// 将cnt第一次出现的位置记录到ind
// 记录第一次出现的位置,是为了后面出现的cnt+1时能离cnt尽可能远,这样计算的时间段越长
ind.set(cnt, i)
// 记录cnt的前缀和
// cnt+1的前缀和计算是 cnt的前缀和+(cnt+1的位置)-(cnt的位置)
sum.has(cnt - 1) ? sum.set(cnt, sum.get(cnt - 1) + i - ind.get(cnt - 1)) : sum.set(cnt, 0)
}
// 如果cnt-1存在,更新max的值
// 如果不存在,则说明当前位置没有表现良好的时间段
if(sum.has(cnt - 1)) max = Math.max(max, sum.get(cnt - 1) + i - ind.get(cnt - 1))
}
// 返回最大值
return max
};
以上为本题的解答过程,如果有问题,欢迎提出探讨