Sliding Window
Sliding windows provide a fixed width view into a list that moves along the length of the list. If used properly it can reduce the time complexity of a problem.
Implementing a sliding window
const std = @import("std");
pub fn main() void {
const data = [_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 };
const window_size = 4;
// +1 ensures the loop includes the last valid window.
for (0..(data.len - window_size + 1)) |i| {
// window represents a slice of size `window_size` of `data`.
const window = data[i..(i + window_size)];
std.debug.print("Window {d}: {any}\n", .{i, window});
}
}
In the example above we implement a sliding window of size 4 elements on an array of 8 elements. Let’s step through each iteration until we view the entire length of the data
array.
To do this we use the formula data.len - window_size + 1
. Our for
loop starts with 0 and iterates a number of times provided by our formula which tells us how many iterations we’ll need, given a window size, to view the entire length of the array. For the code above this is 0 through 4 (5 iterations).
Let’s step through each iteration to see what’s going on.
Iteration 1 (i=0):
Window => data[0..4]
Output => Window 0: { 1, 2, 3, 4 }
Iteration 2 (i=1):
Window => data[1..5]
Output => Window 1: { 2, 3, 4, 5 }
Iteration 3 (i=2):
Window => data[2..6]
Output => Window 2: { 3, 4, 5, 6 }
Iteration 4 (i=3):
Window => data[3..7]
Output => Window 3: { 4, 5, 6, 7 }
Iteration 5 (i=4):
Window => data[4..8]
Output => Window 4: { 5, 6, 7, 8 }
When are sliding windows useful?
When processing a large list of items or a long stream you can theoretically reduce the time to solve by eliminating unnecessary computations. Each time the window slides you can perform operations on a subset and is typically linear in time complexity.
Some use cases are:
- String matching
- Stream processing
- Time-series data
- Image processing
- Sums and occurrences