Algorithms with C# · Lesson 13

Fixed-size sliding windows

Update a neighboring window by removing one value and adding one value.

How it works

A fixed-size sliding window represents neighboring segments of an array. Recalculating every segment's sum from scratch repeats most additions. When the window moves one position, exactly one value leaves and one enters. Updating those two contributions lets the algorithm inspect every window in a single linear pass.

The first example finds the sum nine at starting index two, where the window contains five, one, and three. The second example contains only negative values and correctly returns negative three. Initializing best to zero would invent an unavailable empty-window result and fail that second contract.

The implementation validates that the size is at least one and no larger than the array. It initializes the first real window, then maintains the invariant that sum equals the current size-element window. The starting index formula converts the entering element's position back to the beginning of that window.

A long accumulator reduces overflow risk compared with summing into int, although any bounded numeric type still needs a range policy for an unrestricted workload. The sample's input arrays and sizes are small. Complexity is linear in the number of values and constant in additional state beyond the input.

Practice with size one, size equal to the full array length, an all-equal array, and two windows sharing the same maximum. Explain why the strict greater-than comparison retains the earliest maximum. Change it to greater-than-or-equal and predict how the tie policy changes.

Finally, implement a simple reference version that sums each window independently. Compare both implementations over a small table of hand-written inputs, including negatives and boundary sizes. The slower reference is useful for checking correctness; the optimized version is justified by its invariant and reduced repeated work rather than by a timing claim from one tiny run.

A working example

using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using System.Runtime.CompilerServices;

var best = Best(new[] { 2, 1, 5, 1, 3, 2 }, 3);
Console.WriteLine($"{best.Sum}:{best.Start}");
Console.WriteLine(Best(new[] { -4, -1, -2, -7 }, 2).Sum);
static (long Sum, int Start) Best(int[] values, int size) {
    if (size < 1 || size > values.Length) throw new ArgumentOutOfRangeException(nameof(size));
    long sum = 0;
    for (int index = 0; index < size; index++) sum += values[index];
    long best = sum; int start = 0;
    for (int index = size; index < values.Length; index++) {
        sum += (long)values[index] - values[index - size];
        if (sum > best) { best = sum; start = index - size + 1; }
    }
    return (best, start);
}

Expected output

9:2
-3
Try this
Initialize the best sum from a real window so all-negative inputs remain correct.