# 862. Shortest Subarray with Sum at Least K

**<font color=red>难度: Hard</font>**

## 刷题内容

> 原题连接

* https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/

> 内容描述

```
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
```

## 解题方案

> 思路 1
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******


首先想到用前缀和数组，对于每一个prefix[i]，找到一个最大的j使得j < i 并且prefix[i] - prefix[j] >= K，
那么i-j就是一个符合题目条件的长度，取所有这样的长度中的最小值即可，如果没有就返回-1

但是这样也是O(N^2)的一个解法，无疑是不行的

优化一下，维护一个deque ```opt```，使得opt(y) = largest x with prefix[x] <= prefix[y] - K

我们发现两个规律：
1. If x1 < x2 and P[x2] <= P[x1], then opt(y) can never be x1, as if P[x1] <= P[y] - K, 
then P[x2] <= P[x1] <= P[y] - K but y - x2 is smaller. 
This implies that our candidates x for opt(y) will have increasing values of P[x].
2. If opt(y1) = x, then we do not need to consider this x again. 
For if we find some y2 > y1 with opt(y2) = x, then it represents an answer of y2 - x which is worse (larger) than y1 - x.


beats 90.53%

```python
class Solution(object):
    def shortestSubarray(self, A, K):
        """
        :type A: List[int]
        :type K: int
        :rtype: int
        """
        A = [0] + A
        prefix = [0] * len(A)
        for i in range(1, len(A)):
            prefix[i] = prefix[i-1] + A[i]
            
        opt = collections.deque() # opt(y) = largest x with prefix[x] <= prefix[y] - K
        res = sys.maxsize
            
        for x2, px2 in enumerate(prefix):
            
            # 规律1: If x1 < x2 and P[x2] <= P[x1], then opt(y) can never be x1
            while opt and px2 <= prefix[opt[-1]]: 
                opt.pop()
                
            # 规律2: If opt(y1) = x, then we do not need to consider this x again. 
            while opt and px2 - prefix[opt[0]] >= K:
                res = min(res, x2 - opt.popleft()) 

            opt.append(x2)

        return res if res != sys.maxsize else -1
```

> 思路 2
******- 时间复杂度: O(N)******- 空间复杂度: O(N)******

同样的原理，我们可以用heapq来实现，参考[cnkyzz](https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/discuss/143850/Python-Simple-and-Readable-AC-Heapq-Solution-w-Detailed-Explanation)

- We cannot use this tuple later as length will always increase as i increases !
- For the current tuple, it might be the new shortest subarray if i - preIndex < l and we update res

beats 15.26%

```python
class Solution(object):
    def shortestSubarray(self, A, K):
        """
        :type A: List[int]
        :type K: int
        :rtype: int
        """
        heap, res, sm = [], sys.maxsize, 0
        heapq.heappush(heap, (0, -1))
        for i, num in enumerate(A):
            sm += num
            diff = sm - K
            while heap and (heap[0][0] <= diff or i - heap[0][1] >= res):
                preSum, preIndex = heapq.heappop(heap)
                if i - preIndex < res:
                    res = i - preIndex
            heapq.heappush(heap, (sm, i))
        return res if res != sys.maxsize else -1
```




























