接下来考虑 q 的性质。我们会往 q 中增加和删除元素。每次增加一个元素 curSum 前,先根据不等式删除一部分元素(也可能不删),然后再删除 q 中所有大于等于 curSum 的元素,这样每次加进去的元素都会是 q 中的唯一最大值,使得 q 中的元素是按照添加顺序严格单调递增的,我们知道单调队列是满足这样的性质的。而这一性质,也可以帮助找到 q 中所有满足不等式的值。按照添加的顺序从早到晚,即元素的值从小到大来比较是否满足不等式即可。按照这个顺序,一旦有一个元素不满足,q 中后续的元素也不会满足不等式,即可停止比较。基于此,我们需要一个集合,可以在两端删除元素,在一端添加元素,因此使用双端队列。
在完成代码时,q 中暂存的元素是 preSumArr 的下标,对应下标的前缀和严格单调递增。
代码
[sol1-Python3]
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defshortestSubarray(self, nums: List[int], k: int) -> int: preSumArr = [0] res = len(nums) + 1 for num in nums: preSumArr.append(preSumArr[-1] + num) q = deque() for i, curSum inenumerate(preSumArr): while q and curSum - preSumArr[q[0]] >= k: res = min(res, i - q.popleft()) while q and preSumArr[q[-1]] >= curSum: q.pop() q.append(i) return res if res < len(nums) + 1else -1
classSolution { public: intshortestSubarray(vector<int>& nums, int k){ int n = nums.size(); vector<long> preSumArr(n + 1); for (int i = 0; i < n; i++) { preSumArr[i + 1] = preSumArr[i] + nums[i]; } int res = n + 1; deque<int> qu; for (int i = 0; i <= n; i++) { long curSum = preSumArr[i]; while (!qu.empty() && curSum - preSumArr[qu.front()] >= k) { res = min(res, i - qu.front()); qu.pop_front(); } while (!qu.empty() && preSumArr[qu.back()] >= curSum) { qu.pop_back(); } qu.push_back(i); } return res < n + 1 ? res : -1; } };
intshortestSubarray(int* nums, int numsSize, int k) { long preSumArr[numsSize + 1]; preSumArr[0] = 0; for (int i = 0; i < numsSize; i++) { preSumArr[i + 1] = preSumArr[i] + nums[i]; } int res = numsSize + 1; MyCircularDeque *queue = myCircularDequeCreate(numsSize + 1); for (int i = 0; i <= numsSize; i++) { long curSum = preSumArr[i]; while (!myCircularDequeIsEmpty(queue) && curSum - preSumArr[myCircularDequeGetFront(queue)] >= k) { res = MIN(res, i - myCircularDequeGetFront(queue)); myCircularDequeDeleteFront(queue); } while (!myCircularDequeIsEmpty(queue) && preSumArr[myCircularDequeGetRear(queue)] >= curSum) { myCircularDequeDeleteLast(queue); } myCircularDequeInsertLast(queue, i); } myCircularDequeFree(queue); return res < numsSize + 1 ? res : -1; }
funcshortestSubarray(nums []int, k int)int { n := len(nums) preSumArr := make([]int, n+1) for i, num := range nums { preSumArr[i+1] = preSumArr[i] + num } ans := n + 1 q := []int{} for i, curSum := range preSumArr { forlen(q) > 0 && curSum-preSumArr[q[0]] >= k { ans = min(ans, i-q[0]) q = q[1:] } forlen(q) > 0 && preSumArr[q[len(q)-1]] >= curSum { q = q[:len(q)-1] } q = append(q, i) } if ans < n+1 { return ans } return-1 }
funcmin(a, b int)int { if a < b { return a } return b }