[路飞]_表现良好的最长时间段

186 阅读1分钟

题目介绍

给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。

我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」。

所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。

请你返回「表现良好时间段」的最大长度。

示例1

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

示例2

输入: hours = [6,6,6]
输出: 0

提示:

解题思路

本题的解题关键在于找出每一项之前 表现良好的最长时间段,然后取出这些 表现良好的最长时间段 中最大的那个

我们拿 [9,9,6,0,6,6,9] 进行说明,首先将每一项根据 大于等于8小时(以下简称“大8”)记为 1,小于8小时(以下简称“小8”)记为 -1,可以得到一个新的数组

1640974403(1).png 假设初始值为0,将新数组的每一项的前n项和相加,所得到的数组的每一项表示的意思是当前项大8比小8多的天数

1640974618(1).png 要找到当前项之前 表现良好的最长时间段,需要将当前项的下标减去 sum 值小于当前项并且离当前项最远的位置下标

假如要找到 sum 值为 1 的 表现良好的最长时间段,需要先找到当前项之前有没有 sum 值为 0 的项,如果找到了,再往前找有没有 sum 值为 -1 的项…… 一直找到找不到为止,那么当前下标与 sum 为 1 的下标之间的差值即为 表现良好的最长时间段

这里可以得出一个有用的结论 sum 为 1 的 表现良好的最长时间段 = sum 为 0 的 表现良好的最长时间段 + sum 为 1 的位置下标 - sum 为 0 的位置下标

依次对 sum 的每一项进行上述计算,然后找出其中最大的值即为最终的结果

1640975140(1).png

1640975155(1).png

解题代码

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
};

以上为本题的解答过程,如果有问题,欢迎提出探讨