[路飞]_算法_前缀和_表现良好的最长时间段

416 阅读2分钟

题目描述

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

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

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

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

示例 1:

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

示例 2:

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

提示:

  • 1 <= hours.length <= 104
  • 0 <= hours[i] <= 16

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/lo… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路

尝试用前缀和的方法来解决 首先题干描述,大于8的是劳累的一天,时间段中大于8的时间大于小于等于8的时间,就是良好时间段,我们求的是最长的良好时间段的长度。 1, 所以,数值不重要,是否大于8才重要,于是,我们把时间数组用1和-1来统计,大于8的记为1,否则记为-1。

  • 原时间数组[9,9,6,0,6,6,9]则变为 newList=[1,1,-1,-1,-1,-1,1]。
  • newList中,一个时间段内的元素加起来>0则这个时间段就是良好时间段,比如[1,1,-1]所有元素和大于0,则是良好时间段

2, 综上,问题简化为求[1,1,-1,-1,-1,-1,1] 中,所有元素和大于0的序列中,长度最长的那个序列长度。 到此,其实可以用暴力解题的方法解答了。

  • 设任意一个下标从i到j的序列段为[i,j],只需要双重遍历找到所有[i,j]序列和大于0的序列段,再比较大小就能得出结果

3, 这里,为了减少时间复杂度,我们优化下,用前缀和的方式来解题。

  • 前缀和,为每个项的值都为前面所有项的和,再加上自己。
  • 以上newList序列转化为前缀和为 addList=[0,1,2,1,0,-1,-2,-1]。
  • 注意这里最前面加了个0是为了比较第一天的情况,i=0,j=1则可表示第一天的情况。

这时候,我们要求原本newList [i,j]之间元素的和就很简单了,在addList中直接用addList数组j项的值减i项的值即可。

代码


/**
 * @param {number[]} hours
 * @return {number}
 */
var longestWPI = function(hours) {
    let addList=[0];//前缀和数组,初始为0
    //一边遍历一边获得数组
    for (let i=0;i<hours.length;i++){
        addList.push(hours[i]>8?addList[i]+1:addList[i]-1);//判断大于8则,在上一项的基础上+1,否则就-1
    }
    //现在就能得到前缀和数组addList
    console.log(addList);//[0,1,2,1,0,-1,-2,-1] 与预期相同
    //双重遍历addList里所有i到j的差,找出满足addList[j]-addList[i]>0,且j-i跨度最大的,就是最长的表现良好时间
    let result=0;
    let n=addList.length;
    for(let i=0;i<n;i++){
        for(let j=0;j<n;j++){
            if(j>i&&addList[j]-addList[i]>0){
                //判断满足良好时间段,再和现有的良好时间段长度比较,取大值
                result=Math.max(result,j-i);
            }
        
      }
    }
    return result;
};

总结

此代码提交结果,性能排名较低,待优化