#209 Minimum Size Subarray Sum
Sliding Window
Given an array of n positive integers and a positive
integer s, find the minimal length of a contiguous subarray
of which the sum ≥ s. If there isn't one, return 0 instead.
Example:
Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length
under the problem constraint.
/**
* @param {number} s
* @param {number[]} nums
* @return {number}
*/
var minSubArrayLen = function(s, nums) {}
擷取自 Leetcode 刷題 pattern - Sliding Window
Sliding Window 解法
如果我們仔細觀察暴力法的過程,就會發現有很多 subarray sum 是重複計算的!我們看看下面這個例子
nums = [2,3,1,2,4,3]
暴力法列舉出的 subarrays =
[2]
[2,3]
[2,3,1]
[2,3,1,2]
[2,3,1,2,4]
[2,3,1,2,4,3]
[3]
[3,1]
[3,1,2]
[3,1,2,4]
[3,1,2,4,3]
...
...
不難發現,其實以 2 為開頭的 subarray 跟以 3 為開頭的 subarray 其實只差在開頭有沒有那個 2,後面的數值應該要可以重複利用!
所以我們可以用 windowStart 跟 windowEnd 兩個指向 subarray 邊界的指針,來控制我們現在要看的 subarray。演算法就是要先一直擴張 windowEnd,如果發現 windowSum 已經比 s 大,那就開始縮減 window(也就是把 windowStart 往右移),直到走到 nums 的尾巴。實做出來的程式碼如下
var minSubArrayLen = function(s, nums) {
let min = Number.MAX_SAFE_INTEGER;
let sum = 0, start = 0;
for(let end = 0; end < nums.length; end++){
sum += nums[end];
while(sum >= s){
min = Math.min(min, end - start + 1);
// 也就是把 windowStart 往右移
sum -= nums[start];
start ++;
}
}
return min == Number.MAX_SAFE_INTEGER ? 0 : min;
};
使用這個方法,就完全去除掉冗餘的計算,讓時間複雜度下降到 O(n)O(n)!剛開始學到這個演算法的時候會懷疑這樣真的能走過所有可能的 subarray 嗎?
我覺得大家可以透過這個例子觀察
nums = [2,3,1,2,4,3], s = 7
暴力法列舉出的 subarrays =
[2]
[2,3]
[2,3,1]
[2,3,1,2] // WindowStart 會開始往右移
[2,3,1,2,4]
[2,3,1,2,4,3]
...
一開始 windowStart 指向 2,然後 windowEnd 會慢慢擴張,當擴張到 [2,3,1,2] 這個情況時,因為 sum 已經 >= 7,所以 windowStart 會開始右移。也就是說,原本暴力法會考慮的 [2,3,1,2,4] 跟 [2,3,1,2,4,3] 就不會被考慮到。
就是因為這種情況,直觀下會覺得我們這樣不就少考慮到很多情況嗎?
但大家可以再仔細想想,我們現在要求的是 sum >= s 的最小 subarray,如果 [2,3,1,2] 已經滿足條件了,我們繼續看 [2,3,1,2,4] 跟 [2,3,1,2,4,3] 又有什麼意義呢?畢竟這兩個 subarray 都大於 [2,3,1,2] 啊!
只要把這點想通了,就不會再有用 Sliding Window 沒有考慮到所有 case 的這種讓心裡隱約覺得不對的想法!接著讓我們繼續看下去,更加熟悉 Sliding Window 可以應用的場景。
Last updated
Was this helpful?