[M单调栈] lc1124. 表现良好的最长时间段(单调栈+新思路+反向遍历)

Posted Ypuyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[M单调栈] lc1124. 表现良好的最长时间段(单调栈+新思路+反向遍历)相关的知识,希望对你有一定的参考价值。

文章目录

1. 题目来源

链接:1124. 表现良好的最长时间段

2. 题目解析

很惊艳的一道题目。推荐给几个朋友,大家都觉得很不错,好题。本题也是到了 1908 的分数了。

计算区间和,应当快速想到前缀和。

转换 nums 数组将劳累的一天元素位置置为 1, 不劳累的一天元素位置置为 -1,这样问题就变成了:nums 数组中最长的子数组,且元素和大于 0。

如何快速确定左右端点,来确定这个子数组呢?

双指针?滑动窗口? 在此需要考虑一下单调栈。

已知前缀和数组 s,则 [i, j] 就是 s[j] - s[i-1],顺序遍历 s,针对 s[i] 维护单调递减栈,然后在 逆序遍历 s,当我们发现 s[j] 大于栈顶元素时,就说明找到了一个答案,即子数组元素和大于 0 ,则更新答案,栈顶元素出栈


感觉很难想到并联想到单调栈哈…

因为本题要求的是,左端点一定是要小于右端点的,还要将有效区间段尽可能的求出来,来更新答案。

单调栈这样求法,不会求得所有的满足答案要求的区间段,但是 那些被忽略的区间段,已经不会用来更新最值了。

感觉灵神的题解十分清晰,%%%


  • 时间复杂度 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n)

class Solution 
public:
    int longestWPI(vector<int> &hours) 
        int n = hours.size(), ans = 0, s[n + 1]; 

        stack<int> st;
        st.push(s[0] = 0);
        for (int j = 1; j <= n; j ++ ) 
            s[j] = s[j - 1] + (hours[j - 1] > 8 ? 1 : -1);
            if (s[j] < s[st.top()]) st.push(j); // 顺序遍历,维护单调递减栈
        

        // 倒序遍历更新最大值,相当巧妙。
        // 如果我更新了一次最大值,那么后续的数字,跟这个栈顶元素一定不是最大长度,故可以栈顶出栈,尝试拓展区间长度
        for (int i = n; i; i -- )
            while (!st.empty() && s[i] > s[st.top()]) 
                ans = max(ans, i - st.top()); // [栈顶,i) 可能是最长子数组
                st.pop();
            
        return ans;
    
;

以上是关于[M单调栈] lc1124. 表现良好的最长时间段(单调栈+新思路+反向遍历)的主要内容,如果未能解决你的问题,请参考以下文章

[LeetCode] 1124. Longest Well-Performing Interval 表现良好的最长时间段

LC 3. 无重复字符的最长子串

[H单调栈] lc5196. 队列中可以看到的人数(单调栈+双周赛57_4)

LC6227.下一个更大元素 IV(双单调栈||set||线段树)

算法 LC 动态规划 - 最大递增子序列

5129. 表现良好的最长时间段(数组)