【LeetCode】1124.表现良好的最长时间段
【LeetCode】1124.表现良好的最长时间段
题目链接:1124.表现良好的最长时间段
前缀和
什么是前缀和:【算法】前缀和
我们计工作时间超过8小时为1,否则为-1,那么所谓的“表现良好的时间段”就是和大于0的区间。
暴力-0
最简单的方法是遍历所有可能的区间,判断是否和大于零,并返回和大于零的区间最大长度。
暴力-1
对暴力-0进行优化,由于是寻找最长的区间,固定区间左端,右端从大到小遍历,只要找到一个就行,然后左端移动,重复进行,则每一个左端对应一个长度,其中最长的即为所求。
暴力-2
继续优化,在循环中动态更新结果result,在大循环中,如果剩余的总长度不够result,不可能再找出比result更大的结果,直接返回。
暴力-3
我们也可以固定右端right,这样的话并没有对算法进行优化,但是更好理解。
我们用数组s表示前缀和,score表示正负一数组,则 \(\sum_{j=0}^{i-1}score[j]=s[i]\)。
那么我们的目标是找到左端left和右端right,使得 \(s[right]-s[left]>0\) 并且 \(right-left\) 最大。
由于我们固定了右端,初始情况下,\(left\) 为0,那么只要 \(s[right]>0\),那么对应的最长长度为 \(right\),而且这种情况下,后续移动右端将不会有更长的区间,直接判断 \(right\) 和 \(result\) 中更大的,如果 \(right\) 已经比 \(result\) 小,也是同理,直接返回 \(result\)。
如果 \(s[right]<0\),则需要找到最小的 \(left\),使得 \(left<right\) 且 \(s[right]>s[left]\)。由于s中的元素都是-1和1,当left从0增大,\(s[right]-s[left] < 0\) 每次以连续整数向 \(s[right]-s[left] > 0\) 变化,则最小满足条件的left一定有 \(s[right]-s[left] == 1\)。即,寻找最小的 \(left<right\) 使得 \(s[right]-s[left] == 1\),和【LeetCode】1.两数之和类似,使用hash表进行优化。
class Solution:
def longestWPI(self, hours: List[int]) -> int:
result = 0
score = 0
hashmap = {}
for i in range(len(hours)):
score = score + (1 if hours[i] > 8 else -1)
if score not in hashmap:
hashmap[score] = i
if score > 0:
result = max(i+1, result)
elif score-1 in hashmap:
result = max(i-hashmap[score-1], result)
return result