What patterns have we seen so far?
Given a list [a b c d e f g h], let’s slide a window of 3 elements wide:
[a b c d e f g h]
Here goes the window through the loop:
[a b c] -> first iteration
[b c d]
[c d e]
[d e f]
[e f g]
[f g h] -> last iteration
Sliding window works by making use of something called an
optimal substructure.
The TL;DR is that if you break a problem into sub-problems and solve those, you’ll get the solution to the original problem.
In our case, one of the possible “windows” is the solution to the problem.
Sliding window works by reducing an O(n^2) approach to O(n).
Examples include:
In general, look for the keywords subarray or substring, and see if the naive solution is O(n^2). This may be an indication to use sliding window.
Write a function called maxSubarraySum, which accepts an array of integers and a number representing the length of a subarray.
The function should return the largest sum of a contiguous subarray
with the given length.
Note that a subarray must consist of
consecutive elements from the original array.
maxSubarraySum([100, 200, 300, 400], 2); // 700
maxSubarraySum([1, 4, 2, 10, 23, 3, 1, 0, 20], 4); // 39
maxSubarraySum([-3, 4, 0, -2, 6, -1], 2); // 5
maxSubarraySum([3, -2, 7, -4, 1, -1, 4, -2, 1], 2); // 5
maxSubarraySum([2, 3], 3); // null
In the example above, [100, 200]
is a valid subarray of the original array, but [100, 300]
is not, because 100 and 300 are not consecutive.
Compute the sum for every possible sub-array with size k at every index.
function maxSubarraySum(arr, k) {
let maxSum = 0;
for (let i = 0; i <= arr.length - k; i++) {
// sum every k elements starting from current i
let currentSum = 0;
for (let j = i; j < i + k; j++) {
currentSum += arr[j];
}
// is this the largest slice so far?
maxSum = Math.max(currentSum, maxSum);
}
return maxSum;
}
Time Complexity: O(n^2)
For ([-3, 2, 3, -1, 5, 1], 3)
as input,
How many times did we add three to a currentSum?
How many times did we do 3 + -1?
We’re doing the same work over and over, re-adding elements that we’ve already added before…
For ([-3, 2, 3, -1, 5, 1], 3)
as input, look at the iterations:
Instead of re-adding the same numbers each time,
let’s just keep a running total with a sliding window.
function maxSubarrSum(arr, k) {
let maxSum = 0;
// get the sum of the first three numbers to start
for (let i = 0; i < k; i++) {
maxSum += arr[i];
}
let currentSum = maxSum;
// starting after the first sum, compute the rest
for (let i = k; i < arr.length; i++) {
// current window adds new element and chops off left
currentSum += arr[i] - arr[i - k];
maxSum = Math.max(maxSum, currentSum);
}
return maxSum;
}
Time Complexity: O(N)
The window adds one to the right and subtracts one to the left in each iteration instead of doing a nested loop to recalculate the sums.
For ([-3, 2, 3, -1, 5, 1], 3)
as input…
Every iteration uses the currentSum of the last iteration
but slides the window.
How did we solve maxSubarraySum with sliding window?