0
点赞
收藏
分享

微信扫一扫

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】


目录

​​一,题目描述​​

​​英文描述​​

​​中文描述​​

​​示例与说明​​

​​二,解题思路​​

​​1,前缀和数组​​

​​2,优化过程​​

​​三,AC代码​​

​​C++​​

​​Java​​

​​四,解题过程​​

​​第一博 ​​

​​第二搏​​

一,题目描述

英文描述

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.

中文描述

给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。

我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」。

所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。

请你返回「表现良好时间段」的最大长度。

示例与说明

示例 1:

输入:hours = [9,9,6,0,6,6,9]
输出:3
解释:最长的表现良好时间段是 [9,9,6]。
 

提示:

1 <= hours.length <= 10000
0 <= hours[i] <= 16

来源:力扣(LeetCode)
链接:​​​力扣​​ 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二,解题思路

参考​​@见习魔法师~【参考了几个大神的题解之后总结下来非常详细的解题思路, 希望大家少走些弯路】​​讲的非常详细,包括算法思路以及一步步怎么优化的。(截图内容均来自于此文章)

这里再简单记录一下。

1,前缀和数组

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_中等

说明几点:

1,前缀和数组prefixSum比原数组arr长度要大一,主要是为了简化后面的操作,并且方便理解(可以看作哨兵)。比如prefisSum[i]即表示前i(而不是i+1)个元素的和。


2,由于前缀和数组prefixSum比原数组arr长度要大一,那么索引的对应关系如下

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_算法_02

所以有arr[2]+arr[3]+...+arr[5]==prefixSum[6] - prefixSum[2] 。也就是后面代码中直接用j-i与ans对比(而不是j-i+1),并替换原ans。

因为prefixSum[6] - prefixSum[2]求的就是Arr数组中下标2、3、4、5这四个索引对应的元素和,而与Arr数组中下标为1的元素无关,因此用 j-i 而不是 j-i+1 。

2,优化过程

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_中等_03

说明几点:

1,为什么引入递减序列?

其实关键在于“寻找满足prefixSum[j] - prefixSum[i] > 0 的最大j - i”,也就是只要前缀和之差大于零,i和j距离越远越好。

观察下面的红色点位:

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_算法_04

i点位与i1和i2之间,且

  • prefixSum[ i ]>prefixSum[ i1 ],prefixSum[ i ]>prefixSum[ i2 ]
  • prefixSum[ j ]>prefixSum[ i1 ],prefixSum[ j ]>prefixSum[ i2 ]

prefixSum[ i ]不但大(prefixSum[ i ]越大,越不利于prefixSum[ j ] > prefixSum[ i ]),而且位置 i 相比于 i1 ,其与 j 之间的距离也并不算长。

不难发现,位与 i1 与 i2 之间的点都符合上面的描述,因此,全部可以pass!是不是很兴奋q(≧▽≦q)

2,位置 j 小于递减序列中的点怎么办?

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_leetcode_05

j 从后向前遍历时,会跳过绿色的点(什么也不做,栈中的元素也不会弹出),i仍会停留在原先的位置 

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_数组_06

此时prefixSum[ j ] > prefixSum[ i ],执行ans = max(ans, j - i),递减序列中的数据会逐个弹出。显然此时j - i  < 0,所以不会对ans产生影响!

三,AC代码

C++

class Solution {
public:
int longestWPI(vector<int>& hours) {
vector<int> preSum(hours.size() + 1, 0); // 前缀和数组
vector<int> stack; // 存放递减序列的索引
// 获得前缀和数组
for (int i = 0; i < hours.size(); i++) {
if (hours[i] > 8) preSum[i + 1] = preSum[i] + 1;
else preSum[i + 1] =preSum[i] -1;
}
stack.push_back(0);
// 获得递减序列的堆栈
for (int i = 1; i < preSum.size(); i++) {
if (preSum[i] < preSum[stack.back()]) stack.push_back(i);
}
int ans = 0;
for (int i = preSum.size() - 1; i >= 0; i--) {
while (!stack.empty() && preSum[i] > preSum[stack.back()]) {
ans = max(ans, i - stack.back());
stack.pop_back();
}
}
return ans;
}
};

Java

class Solution {
public int longestWPI(int[] hours) {
int[] presum = new int[hours.length + 1];// 前缀和数组(比原数组长度大一,留一个初始值的位置)
// 将大于8的元素替换为1,其他替换为-1.并获得前缀和数组
for (int i = 0; i < hours.length; i++) {
if (hours[i] > 8) presum[i + 1] = 1;
else presum[i + 1] = -1;
presum[i + 1] += presum[i];
}
// 根据presum获得严格递减的元素索引,并存入栈中
Deque<Integer> stack = new LinkedList<>();
stack.push(0);
for (int i = 1; i < presum.length; i++) {
if (presum[i] < presum[stack.peek()]) stack.push(i);
}
// 从后向前遍历presum数组,获得结果
int ans = 0;
for (int i = presum.length - 1; i >= 0; i--) {
while (!stack.isEmpty() && presum[i] > presum[stack.peek()]) {
ans = Math.max(ans, i - stack.peek());// 这里不是i - stack.peek() + 1
stack.pop();
}
}
return ans;
}
}

四,解题过程

第一博 

直接暴力解决,双重循环不放过任何一个可能的解,当然运行结果可想而知

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_算法_07

class Solution {
public int longestWPI(int[] hours) {
int ans = 0;
for(int i = 0; i < hours.length; i++) {
int goodDays = 0;
for(int j = i; j < hours.length; j++) {
if (hours[j] > 8) goodDays++;
else goodDays--;
if (goodDays > 0) ans = Math.max(ans, j - i + 1);
}
}
return ans;
}
}

第二搏

参考了大神的思路,使用栈(严格来说不是单调栈)的方法完美解决。

LeetCode_Stack_1124. Longest Well-Performing Interval 表现良好的最长时间段【栈】【中等】_栈_08

举报

相关推荐

0 条评论