1. 程式人生 > >leetcode 862. 和至少為K的最短子陣列

leetcode 862. 和至少為K的最短子陣列

1 題目描述

返回 A 的最短的非空連續子陣列的長度,該子陣列的和至少為 K 。

如果沒有和至少為 K 的非空子陣列,返回 -1 。

示例 1:

輸入:A = [1], K = 1 輸出:1

示例 2:

輸入:A = [1,2], K = 4 輸出:-1

示例 3:

輸入:A = [2,-1,2], K = 3 輸出:3

提示:

1 <= A.length <= 50000 -10 ^ 5 <= A[i] <= 10 ^ 5 1 <= K <= 10 ^ 9

2 思路

我沒什麼思路,我好菜啊。我只能在O(N)時間內計算A的累積和陣列sums,這樣任意指定兩個位置都能計算他們之間所有數的和。我只想到了O(N^2)的複雜度的解法。 我在網上看了別人的解法,他們好厲害啊。

https://www.jianshu.com/p/f80e7bc7af7b

有一個雙端佇列deque,變數i從0開始到n(包含)遍歷,佇列中存放的是[0,i][0,i]之間可能的開始位置,i為結束位置。如果deque[0]滿足條件(就是deuqe[0]開始,i結束的字陣列和至少為K),就刪除它,然後再迴圈判斷,直到deque[0]不滿足條件。deque中位置對應的值是從小到大的,0不滿足,後面更不可能滿足,所以不用再判斷。如果i比隊尾元素小或相等,就刪除隊尾,迴圈判斷,直到i比隊尾元素大。

import java.util.ArrayDeque;
import java.util.Deque;

class Solution {
    public int shortestSubarray(int[] A, int K) {
        int n = A.length;
        // A的累計和陣列,sums[i] = sums(A[0]+A[1]+...+A[i])
        int[] sums = new int[n+1];
        sums[0] = 0;
        for (int i = 1; i <= n; i++) {
            sums[i] = sums[i-1]+A[i-1];
        }

        int minWindowSize = n+1;
        Deque<Integer> deque = new ArrayDeque<Integer>();
        for (int i = 0; i <= n; i++) {
            while (!deque.isEmpty() && sums[i] - sums[deque.getFirst()] >= K) {
                minWindowSize = Integer.min(minWindowSize, i-deque.getFirst());
                deque.removeFirst();
            }
            while (!deque.isEmpty() && sums[i] <= sums[deque.getLast()]) {
                deque.removeLast();
            }
            deque.add(i);
        }

        if (minWindowSize == n+1) return -1;
        return minWindowSize;
    }
}