- 表现良好的最长时间段
给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数。
我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是「劳累的一天」。
所谓「表现良好的时间段」,意味在这段时间内,「劳累的天数」是严格 大于「不劳累的天数」。
请你返回「表现良好时间段」的最大长度。
示例 1:
输入:hours = [9,9,6,0,6,6,9]
输出:3
解释:最长的表现良好时间段是 [9,9,6]。
理解:题中所求的是 「劳累的天数」 大于「不劳累的天数」 ,设大于8(即劳累)的值为1,小于8(不劳累)的值为-1,则总的来说就是求最长连续字串的和大于0.
法1:暴力
按照上面的思路先将其用1和-1表示每一天的状态赋值到一个新的数组a[]中。再通过遍历,每次比较 max = Math.max(max, j - i + 1);
从而得到max
的最大值,return max
即可
class Solution {
public int longestWPI(int[] hours) {
int n = hours.length;
int[] a = new int[n];
int sum = 0;
int max = 0;
for (int i=0;i<n;i++) {
if (hours[i] > 8) {
a[i] = -1;
} else {
a[i] = 1;
}
}
for (int i=0;i<n;i++) {
for (int j=i;j<n;j++) {
sum += a[j];
if (sum < 0) {
max = Math.max(max, j - i + 1);
}
}
sum = 0;
}
return max;
}
}
法二,前缀和+单调栈
仍然先将其按照1和-1的方式赋值到score[]数组中,再由score数组
得到前缀和presum数组
,其中前缀和是指不含当前下标的值的前缀相加,所以这里的presum数组大小为n+1,比hours的数组大小要大1
.
以hours = [9,9,6,0,6,6,9]
为例子,score = [1, 1, -1, -1, -1, -1, 1]
,然后我们对得分数组计算前缀和 presum = [0, 1, 2, 1, 0, -1, -2, -1]
。因为要寻找的是大于0的最长,然后我们用一个单调递减栈stack
来存储presum
中的单调递减的下标,其中单调递减栈是指栈中元素按照从栈顶到栈底的顺序依次递减
。这里发现presum = [0, 1, 2, 1, 0, -1, -2, -1]
中递减的值为0,-1,-2,其对应的下标分别为0,5,6.故将其下标0,5,6分别压入栈。这时候再将presum
中的元素的值由后到前与栈中元素下标在presum中对应的值进行比较。presum[i] > presum[stack.peek()]
,如果满足该条件则表示当前i到stack.peek()之间是满足条件的。依此类推。如果不满足该条件,则出栈。
class Solution {
public int longestWPI(int[] hours) {
int n = hours.length;
int[] score = new int[n];
for (int i=0;i<n;i++) {
if (hours[i] > 8) score[i] = 1;
else score[i] = -1;
}
int[] presum = new int[n + 1];
presum[0] = 0;
for (int i=1;i<n+1;i++) {
presum[i] = presum[i - 1] + score[i - 1];
}
int result = 0;
Stack<Integer> stack = new Stack<Integer>();
stack.push(0);
for (int i=1;i<n+1;i++) {
if (stack.isEmpty() || presum[stack.peek()] > presum[i]) {
stack.push(i);
}
}
for (int i=n;i>=0;i--) {
while(!stack.isEmpty() && presum[i] > presum[stack.peek()]) {
result = Math.max(result, i - stack.pop());
}
}
return result;
}
}