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:单调栈。

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

相关推荐
战族狼魂3 小时前
高频面试题精选:分治与AI Agent架构
人工智能·算法·大模型·大语言模型
李剑一3 小时前
你用过网易的将军令嘛?它底层实现账号保护的原理相当简单粗暴
算法
Scott9999HH3 小时前
告别流量波动玄学!从法拉第电磁定律到底层 C/C++ 流量累积算法,深度解密工业级电磁流量计选型与开发
c语言·c++·算法
中达瑞和-高光谱·多光谱4 小时前
1nm到8nm光谱分辨率,你的应用该选哪款光谱相机?
算法·高光谱·高光谱相机
ChaoZiLL5 小时前
我的数据结构4-栈和队列
数据结构
香辣牛肉饭5 小时前
【算法】动态规划 最长公共子序列(LCS)
经验分享·笔记·算法·动态规划
miller-tsunami5 小时前
顺序表相关知识点
数据结构·顺序表
旖-旎5 小时前
LeetCode 279:完全平方数(完全背包)—— 题解
c++·算法·leetcode·动态规划·背包问题
.徐十三.6 小时前
一篇文章看到最短路径——Dijkstra算法
算法