A sliding window maintains information about a contiguous range while advancing its boundaries, reusing work from the previous range.
Java sliding windows: fixed-size range totals
Java 8+. The program uses only JDK classes and runs without a framework.
Remove the departing value before adding the next
A depot reports the largest parcel total across any three consecutive hours. Recomputing every three-hour sum works, but it repeats addition of overlapping values. Maintain one running total: subtract the hour leaving the range and add the next hour entering it.
The program accepts a window width rather than hard-coding three. It rejects zero width and widths beyond the input length because neither describes a complete requested range. It initializes the best result from the first real window, so negative-valued data would not incorrectly produce a zero maximum.
A fixed-size window is not the same algorithm as a variable-size window constrained by a target sum. A shrinking rule based on increasing sums generally requires non-negative values. Negative inputs can break that monotonic argument, even though a fixed-width rolling sum remains valid.
Return enough information for the caller
This API returns only the maximum total. A report that must highlight the winning hours also needs the start index, and a tie policy: first, last or all matching ranges. Store those decisions explicitly instead of trying to recover a range later from the total alone.
The accumulator is long, while each measurement is int. That avoids ordinary int sum overflow for a feasible int-array length. A stream with an unbounded lifetime or long measurements needs a separate overflow policy. Read decimal arithmetic if the readings represent money with fractional units.
Working program
public class BusiestHours {
static long maximum(int[] hourlyParcels, int width) {
if (width < 1 || width > hourlyParcels.length) {
throw new IllegalArgumentException("Invalid window width");
}
long total = 0;
for (int hour = 0; hour < width; hour++) total += hourlyParcels[hour];
long best = total;
for (int hour = width; hour < hourlyParcels.length; hour++) {
total -= hourlyParcels[hour - width];
total += hourlyParcels[hour];
best = Math.max(best, total);
}
return best;
}
public static void main(String[] args) {
System.out.println("peak=" + maximum(new int[]{4, 2, 7, 1, 6, 3}, 3));
System.out.println("negative=" + maximum(new int[]{-8, -3, -6}, 2));
}
}Output
peak=14
negative=-9Cost and failure boundaries
The initial window costs O(w), followed by O(n-w) constant-work shifts. Total time is O(n), with O(1) extra working storage. A direct recalculation approach takes O(nw) work. Both inspect the same ranges, so compare their outputs on small random arrays to catch boundary mistakes.
A streaming implementation cannot reread hourlyParcels[hour-width]; it needs a ring buffer or queue holding the departing values, using O(w) storage. The array version’s constant extra space depends on retaining the input. Do not reuse that claim for a streaming adaptation that stores a window.
Common Mistakes
- Do not start the best total at zero when all windows can be negative.
- Do not accept a width that cannot form one complete range.
- Do not assume every variable-window condition works with negative values.
Connect the contracts
Compare the boundary explained in Array bounds with the assumptions made by this program.
Compare the boundary explained in Movement proofs with the assumptions made by this program.
Continue with range and graph boundaries
Continue with Java prefix sums: answer repeated half-open range totals, Java sliding-window maximum: evict expired indices and weaker tails.
