题目如下
数据范围
这题的代码好些但是思路十分复杂如果代码再难一点估计就是困难题了,我愿称为中等的困难题。
本题可以用另一个角度来思考,令超8小时为1否则为-1令pre[i]为i天之前的和即pre是前缀和数组。那么当i小于等于j时有pre[j] - pre[i]大于0 i j这段时间即为良好时间段。所以我们只要在此基础之上找到j - i的最大值即可。
现在假设我们正在遍历数组的第j个元素我们的目标就是找到合适的i那么我们便需要一个数据结构来存储从0开始的递减数列,显然只有单调栈能做到这个要求。那么这里有必要思考一下为什么是从0开始的序列而非任意一个位置开始的序列了:
我们先假设数组存在两个递减序列,同时我们固定j因为我们目标是找j对应的i,
令in(x)为x对应的数组下标
两个序列分别是An,Bm 那么我们令An从0开始即A1 = 0;(注意 An序列是第一个生成的其序列必然包含最小值,对于像Bm这样的序列不能与An有重复)
设in(B1) > in(A1)显然B1 >= A1 (因为B1 小于A1那么B1应该在A序列中与假设矛盾)
那么现在我们假设j对应的pre值大于A1 B1显然由于in(B1) > in(A1) 所以A1才是最优解。
我们可以把情况往普遍方向推 反证法:
假设存在i是j的最优解且i是B序列的即有(0 <= k < i)的数均大于Bi(不能等于哦因为是最优解一旦等于就会有更长的区间)诶这与我们之前假设的矛盾因为从0到i i对应的前缀pre[i]是这个小区间的最小值且不在A序列中,但是这不是巧了吗A序列必然包含这个小区间的最小值(很显然)所以矛盾 故最优解必然存在于A序列之中。
tips:在遍历j时从后往前 因为这样可以避免重复计算。证明就借用leetcode官方的过程这里不是本题的难点。
这里的r指的就是刚才的j。
通过代码
class Solution {
public:int longestWPI(vector<int>& hours) {int n = hours.size();vector<int> pre(n + 1);stack<int> stack;int ans = 0;stack.push(0);for (int i = 1; i <= n; i++) {pre[i] = pre[i - 1] + (hours[i - 1] > 8? 1 : -1);if (pre[stack.top()] > pre[i]) {stack.push(i);}}for (int i = n; i > 0; i--) {while (stack.size()&&pre[stack.top()] < pre[i]) {ans = max(ans, i - stack.top());stack.pop();}}return ans;}
};