Leetcode 862

找到最短的連續子數組的和至少爲k

 

維護前綴和b,那麼要我們要找的就是滿足b[i] - b[j] >=k 的最大的j是多少,樸素的實現的話複雜度是O(N^2)的

注意到如果前綴和b[x] >= b[y]的話,那麼x永遠不可能成爲解,因爲這個時候如果x滿足 b[i] - b[x] >= k的話,

那麼j也一定滿足b[i] - b[y] >= k,並且y和i組成的數組要比x和i組成的數組更短

 

因此候選的解一定是一定(嚴格)單調上升的序列,我們可以用一個雙端隊列來實現

具體的話

每次入隊的時候,如果當前和比隊尾的和大,就一直出隊

尋找解的時候,從隊首一直向後找,找到最大的下標即可,之前的就可以出隊了,因爲他們後面也不可能成爲更優的解了。

 

每個下標最多都只會進隊和出隊一次,複雜度是O(N)

    public int shortestSubarray(int[] A, int K) {
        //單調隊列,維護前綴和B[], 如果 B[i] >= B[j], 那麼i永遠不可能成爲最有解
        int len = A.length;
        int[] b = new int[len + 1];
        for (int i = 1; i <= len; i++) b[i] = b[i - 1] + A[i - 1];

        int res = Integer.MAX_VALUE;
        //d是一個雙端隊列,維護的是b數組的下標
        Deque<Integer> d = new ArrayDeque<>();
        d.add(0);
        for (int i = 1; i <= len; i++) {
            while (!d.isEmpty() && b[i] - b[d.getFirst()] >= K) {
                res = Math.min(res, i - d.getFirst());
                d.pollFirst();
            }
            //根據上述的性質,隊列維護的前綴和一定是一個(嚴格)單調上升的
            while (!d.isEmpty() && b[i] <= b[d.getLast()]) {
                d.pollLast();
            }
            d.add(i);
        }
        return res == Integer.MAX_VALUE ? -1 : res;
    }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章