Sliding Window 演算法 簡介

快速解出SubArray的演算法

Juo Penguin
5 min readMar 31, 2021

簡介

主要用來快速找出連續的SubString, SubArray,找出符合條件的最小or最大值。

實際範例

給定一個總和,並從陣列中找出「大於等於」該總和的SubArray的長度「最小值」

Input: sum = 7, nums = [2, 3, 1, 2, 4, 3]
Output: 2
Explanation: SubArray [4, 3]有最小的length
(4 + 3 >= 7)
  • 暴力法

最簡單且直覺的就是「窮盡」所有SubArray,找出所有的可能並進行分別比對,直到找出最小值。

時間複雜度是 O(n³)

const solveBrutally = (arr=[], sum=0) => {
let minLength = Infinity;
if(SUM(arr) < sum) {
return undefined;
}
for (let i = 0; i < arr.length; i++) {
for (let innerIdx = i; innerIdx < arr.length; innerIdx++) {
const subArr = arr.slice(i, innerIdx + 1);
if(SUM(subArr) === sum) {
if(subArr.length < minLength) {
minLength = subArr.length;
}
}
}
}
return minLength;
}
solveBrutally([2, 3, 1, 2, 4, 3], 7) // 2
// 產出所有的SubArray做比較
// [1], [1, 2], [1, 2, 3]...
// [2], [2, 3], [2, 3, 4]...
  • 更好的解法 — Sliding Window

基於暴力法的改良,就是WindowSliding這個演算法。

方法是用「兩個指針」來交替移動找出「交集」,分別是 start (指針的頭)和 end (指針的尾)。就像是窗戶的左邊框框和右邊框框,將其搜尋範圍縮限在這個start和end的範圍之內,而這窗框的大小(size)通常就是問題需要的答案。

之所以能用start和end找出答案,是因為「沒必要」找出所有解答,像是[2, 3, 1, 2] 就已經大於等於7了,那就沒必要找[2, 3, 1, 2, 4],因為長度(length)一定比較上一個還大(我們要找最小長度)。這樣我們可以將start移動到右邊(+= 1)找下一個SubArray的群集,用while迴圈繼續找下去,直到找出最小值。

簡單來說,就是先給定一個固定範圍(窗戶框), 然後這個窗戶會開開關關,窗戶框會左右移動(移動窗戶的同時開關窗戶),只要確保範圍不超過我們問題所要求的值就好。

時間複雜度是 O(n)

const solveBySlidingWindow = (arr=[], sum=0) => {
let sumNow = 0, startNow = 0;
let minSize = Infinity;
for (let endNow = 0; endNow < arr.length; endNow++) {
sumNow += arr[endNow];
while(sumNow >= sum) {
const windowSize = endNow - startNow + 1;
console.log(arr.slice(startNow, endNow + 1)); // 印出目前窗框範圍內的SubArray
minSize = Math.min(minSize, windowSize); // 更新最小size
// 窗框往右移動
sumNow -= arr[startNow]; // 減去原本的start
startNow++; // start往右移動
}
}
return minSize === Infinity ? 0 : minSize;
};
solveBySlidingWindow([2, 3, 1, 2, 4, 3], 7) // 2
// 只產出符合窗框範圍的SubArray做比較(用startNow和endNow取得目前的SubArray)
// [2, 3, 1, 2] start: 0, end: 3
// [3, 1, 2, 4] start: 1, end: 4
// [1, 2, 4] start: 2, end: 4
// [2, 4, 3] start: 3, end: 5
// [4, 3] start: 4, end: 5, 長度最小值

主要參考來源

主要是將以下這篇文章中用c語言寫的範例,轉為JavaScript,並做些簡化與整理。

https://blog.techbridge.cc/2019/09/28/leetcode-pattern-sliding-window/#post-comment-wrapper

--

--

Juo Penguin

不挑食的雜食者,近期的目標是瘦10公斤。