1. 程式人生 > >【LeetCode】862. Shortest Subarray with Sum at Least K 解題報告(C++)

【LeetCode】862. Shortest Subarray with Sum at Least K 解題報告(C++)

作者: 負雪明燭
id: fuxuemingzhu
個人部落格: http://fuxuemingzhu.cn/


目錄

題目地址: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. 1 <= A.length <= 50000
  2. -10 ^ 5 <= A[i] <= 10 ^ 5
  3. 1 <= K <= 10 ^ 9

題目大意

求最短的子陣列長度,使得這個子陣列的和最少為K,如果不存在這樣的子陣列,返回-1.

解題方法

佇列

我嘗試了O(N^2)的解法,果然超時了。也對,題目給出的陣列長度是50000,基本上只有O(N)或者O(NlogN)的時間複雜度才行了。

這個題的做法要感謝lee215和演員的自我修養。下面的內容來自演員的自我修養

分析:

  1. 顯然,我們會想到使用dp[i]記錄sum(A[:i]),那麼這道題就變成了,給定一個數組dp,找到一組i,j,使得dp[j]-dp[i]>=K,且j-i儘量小!
  2. 資料長度達到50000,顯然不能使用O(n^2)複雜度的方法,我們得想辦法讓i,j只走一遍
  3. 用一個簡單的示例來分析,設 A = [4,-1,2,3],,K = 5,那麼dp = [0,4,3,5,8],我們從dp陣列的第2個數開始分析,(假設來了個-1,那麼因為-1比0小,後面任意一個數val如若滿足val-0>K,那麼val+1也一定大於K,且-1所在的位置i顯然能獲得更優解,所以0這個位置就失去了意義),現在考慮示例,來了個4,我們發現4-0小於5,我們怎麼對4進行處理呢,因為考慮到之後或許會出現一個足夠大的數,比如9,那麼4相對於0是更優的,但也有可能只來一個8,那麼4就沒作用了,所以先暫且保留觀察。等到來了一個5以上的數,我們依次對保留的數(目前是0,4)進行判斷得最優解。
  4. 接下來來了個3,那麼根據上面提到的論點,4將會被捨棄,但3比0要大,故此時0,3保留。
  5. 然後來了個5,5-0>=5,故找到一組i,j,記錄下來,然後判斷 5-3>=5 ?如若確實大於,即再次找到一組i,j,若小於,則5保留(考慮到之後或許來了個10),依次類推

思路:

  1. 建立一個佇列記錄保留數字,初始為0
  2. 依次對dp中的數進行分析,如果dp[i] - dp[Q[0]] >= K,則記錄一次i,j
  3. 如果dp[i] < dp[Q[-1]],則捨棄Q[-1]

C++程式碼如下:

class Solution {
public:
    int shortestSubarray(vector<int>& A, int K) {
        const int N = A.size();
        vector<int> preSum(N + 1, 0);
        for (int i = 1; i < N + 1; i++) {
            preSum[i] = preSum[i - 1] + A[i - 1];
        }
        int res = INT_MAX;
        deque<int> q;
        q.push_back(0);
        for (int i = 1; i < N + 1; i++) {
            int a = preSum[i];
            while (!q.empty() && a - preSum[q.front()] >= K) {
                res = min(res, i - q.front());
                q.pop_front();
            }
            while (!q.empty() && a < preSum[q.back()]) {
                q.pop_back();
            }
            q.push_back(i);
        }
        return res == INT_MAX ? -1 : res;
    }
};

參考資料:

https://leetcode.com/problems/shortest-subarray-with-sum-at-least-k/discuss/143726/C%2B%2BJavaPython-O(N)-Using-Deque
https://buptwc.com/2018/07/02/Leetcode-862-Shortest-Subarray-with-Sum-at-Least-K/

日期

2018 年 12 月 20 日 —— 感冒害的我睡不著