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

文章介绍了如何使用单调栈解决一道编程题目,该题目涉及计算区间和,通过将数组转换并利用单调栈找到元素和大于0的最长子数组,从而找出最长的表现良好时间段。算法的时间复杂度和空间复杂度均为O(n),其中n为数组长度。
摘要由CSDN通过智能技术生成

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;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值