Return the length of the shortest, non-empty, contiguous subarray of A
with sum at least K
.
If there is no non-empty subarray with sum at least K
, return -1
.
Example 1:
Input: A = [1], K = 1 Output: 1
Example 2:
Input: A = [1,2], K = 4 Output: -1
Example 3:
Input: A = [2,-1,2], K = 3 Output: 3
Note:
1 <= A.length <= 50000
-10 ^ 5 <= A[i] <= 10 ^ 5
1 <= K <= 10 ^ 9
-----------------------------------------
It's easy to come up with prefix method:
new_prefix-old_prefix >= K => new_prefix[i]>=K+old_prefix[j], therefore,
- min(i-j). So if some j fulfills the filtering condition, larger i won't take j as the candidate. It's a typical deque solution. Of course, we could use leftmost pointer to replace deque. Without deque, we could use binary search instead.
- Filtered by new_prefix[i]>=K+old_prefix[j]. So treat K+old_prefix[j] as monotonic stack. The filtering condition item will be element in the stack!!!
Here're 3 solutions:
Binary Search:
class Solution:
def shortestSubarray(self, A, K):
def upper_bound(arr, target):
l,r = 0,len(arr)-1
while (l <= r):
mid = l + ((r-l)>>1)
if (arr[mid][0] <= target):
l = mid+1
else:
r = mid-1
return l
cur,sta,res = 0,[],len(A)+1
for idx,a in enumerate(A):
cur += a
while (sta and cur+K < sta[-1][0]):
sta.pop()
pos = upper_bound(sta, cur)-1
#print("sta={0} pos={1}".format(sta,pos))
if (pos >= 0):
res = min(res, idx-sta[pos][1])
elif (cur >= K):
res = min(res, idx+1)
sta.append((cur+K,idx))
return -1 if res == len(A)+1 else res
Use leftmost to replace deque:
class Solution:
def shortestSubarray(self, A, K):
cur,sta,res,leftmost = 0,[],len(A)+1,0
for idx,a in enumerate(A):
cur += a
cl = len(sta)
if (cur >= K):
res = min(res, idx + 1)
#print("leftmost={0} sta={1} cur={2}".format(leftmost, sta, cur))
while (leftmost < cl and sta[leftmost][0] <= cur):
res = min(res, idx-sta[leftmost][1])
leftmost += 1
while (len(sta) > leftmost and cur+K < sta[-1][0]):
sta.pop()
sta.append((cur+K,idx))
return -1 if res == len(A)+1 else res
Deque:
def shortestSubarray(self, A, K):
d = collections.deque([[0, 0]])
res, cur = float('inf'), 0
for i, a in enumerate(A):
cur += a
while d and cur - d[0][1] >= K:
res = min(res, i + 1 - d.popleft()[0])
while d and cur <= d[-1][1]:
d.pop()
d.append([i + 1, cur])
return res if res < float('inf') else -1