zoukankan      html  css  js  c++  java
  • [LeetCode 862] 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. 1 <= A.length <= 50000
    2. -10 ^ 5 <= A[i] <= 10 ^ 5
    3. 1 <= K <= 10 ^ 9

     

    Input size is up to 5 * 10^4, this makes sliding window to check all subarrays TLE as the runtime is O(N^2).  To compute a subarray's sum, we use prefix sum techique S[L, R] = PS[R] - PS[L - 1]. The shortest subarray must end at one of the element in A, so we can go through A, check each shortest subarray length that ends at A[i]. To compute the shortest length of subarray that ends at A[i] and has total sum >= K, we need to find the largest index j such that PS[i] - PS[j] >= K. There are 2 key observations to help us derive an efficient solution.

    1. for index j and i,  j < i, if prefix sum PS[j] >= PS[i], then for any index k > i, we'll never consider [j, k] as a possible answer. This is because we can always cut off the [j, i - 1] subarray to get a NOT smaller sum and shorter length. 

    2. for index j and i, j < i, if [L1, j] is the shortest subarray with sum >= K and ends at A[j], then to get an even shorter answer that ends at A[i], the starting index L2 of such answer must be L2 > L1. Otherwise we'll have j - L1 < i - L2, this answer is worse than A[j]'s answer. This means the same prefix sum is used at most once to compute a candidate answer.

    With the above analysis, we can come up with two efficient solutions.

    Solution 1. O(N * logN) maintaining an increasing list + binary search solution. 

    Based on observation 1, if store a pair of sum and index for each A[i] in a list,  we know that before we add a new pair, we always remove previous non-smaller sum. This list is always strictly increasing. So we can do a binary search to find the largest index j such that PS[j] <= currSum - K. Then remove previous non-smaller sum entries before appending the current entry to the end of this list.

    class Solution {
        public int shortestSubarray(int[] A, int K) {
            long sum = 0;
            long best = A.length + 1;
            List<long[]> list = new ArrayList<>();
            list.add(new long[]{0, -1});
            
            for(int i = 0; i < A.length; i++) {
                sum += A[i];
                int j = binarySearch(list, sum - K);
                if(j >= 0) {
                    best = Math.min(best, i - list.get(j)[1]);
                }
                while(list.size() > 0 && list.get(list.size() - 1)[0] >= sum) {
                    list.remove(list.size() - 1);
                }
                list.add(new long[]{sum, i});
            }
            return best > A.length ? -1 : (int)best;
        }
    
        private int binarySearch(List<long[]> list, long target) {
            int l = 0, r = list.size() - 1;
            while(l < r - 1) {
                int mid = l + (r - l) / 2;
                long[] e = list.get(mid);
                if(e[0] > target) {
                    r = mid - 1;
                }
                else {
                    l = mid;
                }
            }
            if(list.get(r)[0] <= target) {
                return r;
            }
            else if(list.get(l)[0] <= target) {
                return l;
            }
            return -1;
        }
    }

    Solution 2. O(N) Deque solution.

    An even better solution is to use both observations. We store all pairs in Deque and still remove last non-smaller sums before adding current new pair entry to the end of Deque. So the sums in this deque is still strictly increasing. However, instead of using binary search to find a possible answer, we can just poll from the head of Deque and check if the prefix sum difference is >= K. Keep polling from deque's head until the sum condition can not be met anymore. The last met condition index gives a possible answer for subarray ending at the current element. Observation point 2 tells us that once a prefix sum is used, it'll never be used again, so we do not need to add them back to the deque. Each possible prefix sum pair is added to deque once and polled out of deque at most once, thus the runtime is O(N).

    class Solution {
        public int shortestSubarray(int[] A, int K) {       
            int n = A.length, best = A.length + 1;
            long sum = 0;
            ArrayDeque<Long> dq1 = new ArrayDeque<>();
            ArrayDeque<Integer> dq2 = new ArrayDeque<>();
            dq1.add(0L);
            dq2.add(-1);
            
            for(int i = 0; i < n; i++) {
                sum += A[i];
                int j = A.length;
                while(dq1.size() > 0 && dq1.peekFirst() <= sum - K) {
                    dq1.pollFirst();
                    j = dq2.pollFirst();                
                }
                if(j < A.length) {
                    best = Math.min(best, i - j);
                }
                while(dq1.size() > 0 && dq1.peekLast() >= sum) {
                    dq1.pollLast();
                    dq2.pollLast();
                }
                dq1.addLast(sum);
                dq2.addLast(i);
            }
            return best > A.length ? -1 : best;
        }
    }

    Related Problems

    [LeetCode 209] Minimum Size Subarray Sum

  • 相关阅读:
    [转载]tlb、tlh和tli文件的关系
    [转载]美国不是中国唯一的榜样
    使用spring.net 1.3.2框架部署在虚拟目录上发生错误
    用Log4Net记录NHibernate中执行的SQL语句及执行时间
    IIS7/8 HTTP Error 500.19 错误 0x80070021
    IE下点击scrollbar会导致焦点移动到body
    性能测试学习(一)--基础知识点
    测试基础知识点汇总
    如何制定测试计划
    《软件测试经验与教训》摘录
  • 原文地址:https://www.cnblogs.com/lz87/p/13090858.html
Copyright © 2011-2022 走看看