力扣1124:表现良好的最长时间段
力扣1124:表现良好的最长时间段
- 题目
- 思路
- 代码
题目
给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。
我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」。
所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。
请你返回「表现良好时间段」的最大长度。
思路
想要找到最大长度所以我们要么确定左边界然后寻找符合条件的最右边界,要么就是确定右边界然后寻找符合条件的最左边界。
那么其他的先不谈,怎么才算符合条件。想要劳累的天数严格大于不劳累的天数也就是要满足劳累的天数大于整个天数的二分之一那么我们是否可以把劳累的天数当作1不劳累的天数当作-1同时创建一个整数数组来存储当前位置是否是表现良好的时间段里的一部分也就是说当前位置需要存储前面天中劳累天数是否大于不劳累天数,简单来说就是生成一个前缀和数组。
在有了前缀和数组后我们再来思考在前缀和数组中左边界和右边界有什么关系以及左边界右边界有什么特征,首先右边界的值一定大于左边界不然没法满足劳累的天数严格大于不劳累的天数这是因为在有了前缀和后子数组和元素和问题就转换为了两个前缀和的差值了。其次我们需要关注的左边界一定是一个单调递减的因为一旦左边界变大了之后它就当不了最左边界了,要知道右边界肯定是比左边界大的所以右边界肯定也就大于你前一个位置那你凭啥当最左边界。所以我们需要构建一个数据结构来存储那些不断减小的左边界的位置,我们可以使用栈来当这个数据结构这样也就形成了一个单调栈。每次插入栈我们只需要判断当前位置的值是否小于栈顶的值即可如果小于就插入位置,这样我们就形成了一个从栈底到栈顶单调递减的一个单调栈。在确定可以当最左边界的位置后我们就需要确定右边界的位置了,我们直接从后往前遍历。然后判断当前位置的值是否大于栈顶的值如果大于我们就更新最大长度直到小于栈顶元素,再进行前一个位置的判断。也就是说我们先把最后的位置当作右边界然后进行一轮一轮的判断来确定左边界同时更新最大长度。
代码
class Solution {
public:int longestWPI(vector<int>& hours) {// 栈stack<int> st;int res = 0;int n = hours.size();// 前缀和数组int nums[n + 1];st.push(nums[0] = 0);for (int j = 1; j <= n; j++) {nums[j] = nums[j - 1] + (hours[j-1] > 8 ? 1 : -1);if (nums[j] < nums[st.top()]) {// 从栈底到栈顶的一个单调递减的栈// 也就是有可能为时间段的最左点st.push(j);}}// 从后向前遍历,先确定最右点再确定最左点for (int i = n ; i > 0; i--) {while (!st.empty() && nums[i] > nums[st.top()]) {res = max(res, i - st.top());st.pop();}}return res;}
};