Leetcode 1124. Longest Well-Performing Interval 前缀和数组+hashmap好题

  1. Longest Well-Performing Interval
    Medium
    1.3K
    105
    Companies
    We are given hours, a list of the number of hours worked per day for a given employee.

A day is considered to be a tiring day if and only if the number of hours worked is (strictly) greater than 8.

A well-performing interval is an interval of days for which the number of tiring days is strictly larger than the number of non-tiring days.

Return the length of the longest well-performing interval.

Example 1:

Input: hours = 9,9,6,0,6,6,9

Output: 3

Explanation: The longest well-performing interval is 9,9,6.

Example 2:

Input: hours = 6,6,6

Output: 0

Constraints:

1 <= hours.length <= 104

0 <= hoursi <= 16

解法1:presums\[\] + hashmap。

  1. 先归一化数组。> 8 ->1, <=8 ->-1。这样题目就变成了求最长和>0的子数组。
  2. hashmap存储<presum, index>,这里index是presum出现最早的位置。
  3. 当presumsi > 0时,即为一个解。
  4. 当presumsi<=0时,我们找presumsi-1的那个对应位置即可。
    为什么这个是正确的。举例如下:当presum变成-3时,我们找presum变成-4的最开始的那个位置即可。这里有两种可能性,用 i - mppresums\[i - 1]都是正确的。
    presum变化可能1: 0->-1->-2->-3>-4>-5->-4->-3

    presum变化可能2: 0->-1->-2->-3->-4->-3
cpp 复制代码
class Solution {
public:
    int longestWPI(vector<int>& hours) {
        int n = hours.size();
        vector<int> presums(n + 1, 0);
        unordered_map<int, int> mp; //<presum, index>
        int res = 0;
        for (int i = 1; i <= n; i++) {
            presums[i] = presums[i - 1] + (hours[i - 1] > 8 ? 1 : -1);
        }
        mp[0] = 0;
        for (int i = 1; i <= n; i++) {
            if (presums[i] > 0) {
                res = max(res, i);
            } else {
                if (mp.find(presums[i] - 1) != mp.end()) {
                    res = max(res, i - mp[presums[i] - 1]);
                }
            }
            if (mp.find(presums[i]) == mp.end()) mp[presums[i]] = i;
        }
        return res;
    }
};

解法2:滑动窗口?

我感觉这题不能用滑动窗口。

比如说6,6,6,9,9,9,9,6,6,6,6,6,9,9,9,9,9,9,9,9,一开始都是<=8的,后来又是>8的,然后又是<=8的,然后又是>8的。最优值就是数组长度n。如果要求最大的窗口范围,则right边界从左到右移动完整个数组的时候,left边界都不能移动,一动就错。

我个人的想法:用滑动窗口的场合需要具备某种单调性?那就是如果小窗口符合这个条件,那么包含小窗口的大窗口肯定也符合这个条件。但是这题好像不是,比如说小窗口是>8的数字多,那未必大窗口就是>8的数字多啊。欢迎大家指教。

新想法:为什么不能用滑动窗口呢?因为滑动窗口必须满足目标值的某种单调性,即右边界加入数据,目标值一定会变大或至少不变,左边界移除数据,目标值一定会变小或至少不变,这里的目标值可能是无重复数据的窗口大小等等。这题右边界扩大,有可能是合法的窗口变大,比如说6,9,9变到6,9,9,9,但也可能是合法窗口变小,比如说6,9,9变到6,9,9,6。当我们发现合法窗口变小时,我们也不能移动左窗口,因为实际数据可能是6,9,9,6,9,9,9。

注意:为什么这题可以不可以用滑动窗口,而Leetcode 1004. Max Consecutive Ones III这题就能用呢?

因为Leetcode 1004的滑动窗口满足单调性,即右指针移动直到当前窗口不合格时(即flipCount>k),再移动右指针,当前窗口肯定还是不合格(因为flipCount还是>k)。而这题里面,当我们移动右指针直到当前窗口不合格时(即>8小时的天数小于等于<=8小时的天数),再移动右值时,当前窗口可能又合格了,因为又加入了更多的>8小时的天数。

另外,如果不能用滑动窗口,那我们还是可以用前缀和数组+hashmap来处理。

解法3:单调栈。

注意单调栈是求数组左右侧第一个大于或小于该数的位置。

相关推荐
爱折腾的小黑牛5 分钟前
简记往来批量录入功能的实现:从文本到结构化数据
前端·算法
Starmoon_dhw20 分钟前
题解:P17078 夏日甜点
c++·学习·算法·图论
海石1 小时前
【JS击败90%】前缀和+定长滑动窗口
算法·leetcode
Tisfy1 小时前
LeetCode 2685.统计完全连通分量的数量:DFS求每个连通块的边点数
算法·leetcode·深度优先··题解·连通图·全连通分量
海石1 小时前
1次遍历,空间复杂度击败100%,时间复杂度击败85%
算法·leetcode
L歪歪君2 小时前
Apache Doris全链路性能优化实战指南:从架构设计到生产落地
java·开发语言·算法
m0_466525292 小时前
从“算法内卷”到“可信易用” 东软多模态医学人工智能平台开启无代码科研新时代
人工智能·算法
码少女3 小时前
数据结构——冒泡排序及优化
数据结构·算法·排序算法
梦回江东3 小时前
ansible中的主机清单
算法
青梅橘子皮3 小时前
string---入门OJ题(1)
数据结构·算法