解题思路:
1.用一个 sum 变量记录前缀和,当大于8时,sum++, 小于8时,sum--。
由于从前向后遍历,当 sum > 0时,说明从开始到现在满足条件,时间必然是最长的,直接更新 ans = i + 1。
2.当 sum <= 0时呢?关键来了 :
这里用一个HashMap记录所有 sum <= 0的最小下标,所谓最小,就是后面如果再碰到了同样的 cur,不需要更新,如果没有碰到过,则把这个下标记录下来。因为 sum - x >= 1 , x <= sum -1然后用 sum - 1 去map里找,如果找到了下标 j,那么就说明从0到 j 的前缀和是 sum-1,而从0到 i 的前缀和是 sum,那么显然从 j 到 i 的和是(sum - (sum - 1)) = 1 > 0,也就是说从 j + 1到 i 的表现肯定是满足的,并且由于 j 是 sum-1中最小的,所以 i - j 是最大的。
此时再跟 ans 比较看是否需要更新。
3.上面为什么只需要查找 sum-1?sum - x >= 1 , x <= sum -1 , 因为满足条件的前缀和只能是小于等于sum-1的,也就是说其实也可以查找 sum-2,sum - 3...,但是,sum - 2的下标一定不可能在 sum-1的下标左边。使用反证法,前提是sum -1代表的是最小下标,那么如果 sum - 2在 sum -1左边,而sum - 2的左边一定还会有 sum - 1出现(sum值是从0开始的),这就和最小下标的前提矛盾了。
4. 那么问题又来了,如果 sum-1不存在,是否要查找 sum-2,sum-3...呢?
也不需要,思路跟上面是一样的,如果 sum-1不存在,sum-2,sum-3...一定也不存在。
举个例子,不可能从0跳到-2,-3,而中间没有-1。
作者:li-zi-he
链接:https://leetcode-cn.com/problems/longest-well-performing-interval/solution/bie-gen-lao-fu-ti-shi-yao-dan-diao-zhan-by-li-zi-h/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
这里我画了一个示意图帮助理解上述思想:
class Solution {
public:
int longestWPI(vector<int>& hours)
{
int n = hours.size();
int sum = 0;
int ans = 0;
unordered_map<int, int> index; //用于记录当sum < 0时 ,sum : i下标的映射
for(int i=0;i<n;i++)
{
sum += (hours[i] > 8 ? 1 : -1);
if(sum > 0)
{
ans = i+1;
}
else
{
if(index.count(sum) == 0) //查看是否存在这个sum : i的映射
index[sum] = i; //不存在添加映射关系
if(index.count(sum - 1) != 0) // sum - x =1 ,x = sum - 1;
ans = max(ans , i - index[sum-1]); //找到 key = x的下标
}
}
return ans;
}
};