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,前缀和数组

说明几点:

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

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

所以有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,优化过程

说明几点:

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

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

观察下面的红色点位:

i点位与i1和i2之间,且

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

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

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

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

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

此时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;
    }
}

四,解题过程

第一博 

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

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;
    }
}

第二搏

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

猜你喜欢

转载自blog.csdn.net/qq_41528502/article/details/119915453