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 <= hours[i] <= 16

解法1:presums[] + hashmap。

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

    presum变化可能2: 0->-1->-2->-3->-4->-3
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:单调栈。
注意单调栈是求数组左右侧第一个大于或小于该数的位置。

猜你喜欢

转载自blog.csdn.net/roufoo/article/details/132683351