[M单调栈] lc1124. 表现良好的最长时间段(单调栈+新思路+反向遍历)
Posted Ypuyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[M单调栈] lc1124. 表现良好的最长时间段(单调栈+新思路+反向遍历)相关的知识,希望对你有一定的参考价值。
文章目录
1. 题目来源
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 表现良好的最长时间段
[H单调栈] lc5196. 队列中可以看到的人数(单调栈+双周赛57_4)