Sliding Window — LinkedList Race Condition in Averages
Unsynchronized LinkedList in multi-threaded sliding window caused 15% false alert drop.
20+ years shipping production code across the stack, with years spent interviewing engineers. Everything here is grounded in real deployments.
- ✓Solid grasp of fundamentals
- ✓Comfortable reading code examples
- ✓Basic production concepts
- Sliding window reduces O(n²) nested loops to O(n) by maintaining a window of contiguous elements
- Fixed-size windows always same length, update by subtracting left, adding right in O(1)
- Dynamic windows grow right, shrink left while constraint violated; use while not if
- Performance: each element added once and removed once — total O(n) time, O(1) or O(k) space
- Production insight: wrong shrink logic (if vs while) causes silent data corruption in real-time analytics
- Biggest mistake: using if instead of while for dynamic window shrink — leads to invalid intermediate states
Imagine you're reading a very long receipt from a grocery store, and you need to find the 3 consecutive items that cost the most together. Instead of adding up every possible group of 3 from scratch, you slide a physical 'window' of 3 items across the receipt — dropping one item off the left and picking up one on the right as you go. That's it. A sliding window is just a moving frame over a sequence of data that lets you avoid redundant recalculations.
Sliding window problems show up in almost every technical interview at top-tier companies — not because they're obscure, but because they test whether you think algorithmically or just mechanically. The naive solution to most array and string problems is O(n²) nested loops. The sliding window technique collapses that to O(n), and interviewers use these problems specifically to see if you can make that leap without prompting.
The core problem it solves is this: any time you need to examine a contiguous subarray or substring under some constraint — maximum sum, longest without repeating characters, smallest with a target sum — you're repeatedly looking at overlapping data. Brute force recalculates that overlapping data every single iteration. A sliding window maintains just enough state so you only ever process each element once as the window expands and once as it contracts.
By the end of this article you'll be able to recognise which of the two main window types (fixed-size vs dynamic) applies to a given problem, implement both from memory, handle the edge cases that trip up even experienced candidates, and answer the follow-up questions interviewers use to separate good solutions from great ones.
The Sliding Window: A Pointer Dance That Avoids Recalculation
The sliding window technique maintains a contiguous subarray (or substring) by moving two pointers — left and right — across a linear data structure. Instead of recomputing from scratch for each possible subarray (O(n²) or worse), you update the window's aggregate value incrementally as it expands or contracts. This yields O(n) time and O(1) or O(k) space, where k is the window size.
Two key properties make this work: the window's boundaries move monotonically (no backtracking), and the aggregate function must be efficiently updatable — typically via addition/subtraction (sum, count) or a deque (min, max). The right pointer advances to include new elements; the left pointer advances to exclude old ones when the window violates a constraint (e.g., exceeds a target sum or fixed size).
Use sliding window when the problem asks for a contiguous subarray's property under a constraint — maximum sum of size k, longest substring without repeating characters, or average of every k-length subarray. In production, this pattern appears in real-time metrics (e.g., rolling average latency over the last 1000 requests) where recomputing the full window per event would be too expensive.
Fixed-Size Windows — When the Frame Never Changes
A fixed-size window is the simpler of the two patterns. The window length is given to you upfront and never changes — your only job is to slide it across the array one step at a time and track whatever metric you care about.
The key insight is how you update the window in O(1) instead of O(k): when the window moves one position to the right, exactly one element leaves the left edge and one enters the right edge. That means you don't need to sum (or hash, or count) the whole window again — you just subtract the outgoing element and add the incoming one.
This pattern covers problems like: maximum average subarray of length k, maximum sum subarray of length k, count of anagram occurrences in a string, and find all substrings containing exactly k distinct characters with a fixed length.
The implementation template is always the same: build the first window, record your answer, then loop from index k to n-1, sliding by one each iteration. Get that template into muscle memory and the code almost writes itself.
Dynamic Windows — When the Frame Grows and Shrinks Based on a Condition
Dynamic (or variable-size) windows are where most candidates stumble, because the window doesn't have a fixed length — it grows until it violates a constraint, then shrinks from the left until it's valid again. The two-pointer approach drives this: a right pointer expands the window, and a left pointer contracts it.
The mental model that makes this click: think of the right pointer as greedy and optimistic — it keeps consuming elements hoping to satisfy or maximise the target. The left pointer is the enforcer — when the window breaks the rules, it evicts elements from the left until the window is valid again.
This pattern handles: longest substring without repeating characters, minimum size subarray with sum ≥ target, longest subarray with at most k distinct characters, and fruit into baskets (same idea, different flavour).
The critical implementation detail is the order of operations inside the loop: expand right first, update your state, then shrink left in a while loop until valid, then record your answer. Get that order wrong and you'll record invalid states or miss valid ones — a bug that's devilishly hard to spot under interview pressure.
Recognising the Pattern Fast — The 3-Question Decision Framework
The hardest part of sliding window problems in an interview isn't the code — it's recognising within 60 seconds that sliding window is even the right tool. Interviewers watch this recognition moment closely.
Three questions will get you there every time. First: does the problem involve a contiguous subarray or substring? If the order doesn't matter or elements don't need to be adjacent, sliding window is the wrong tool — reach for a hash map or a sort instead. Second: is there a constraint on the window (sum ≥ target, at most k distinct, no repeating characters)? That constraint is what drives the window's expansion and contraction logic. Third: are you optimising for a minimum or maximum (shortest, longest, smallest, largest)? This tells you whether to update your answer after expanding (maximum) or after contracting (minimum).
For minimum problems — like smallest subarray with sum ≥ target — the trick is you shrink the window as aggressively as possible while still meeting the constraint, updating your best answer after each contraction, not after expansion.
Production-Grade Implementation: Handling Stream Data
In real-world systems, data often arrives as a stream rather than a static array. For these cases, we use specialized data structures or reactive patterns. Below is how you would model a sliding window over a potentially infinite stream of integers using a standard Java queue to represent the window state.
Sliding Window Variants and Space Complexity Considerations
Sliding window can be extended to handle more complex constraints. One common variant is the monotonic queue (deque) based sliding window for problems like sliding window maximum or minimum. Instead of storing all elements, you maintain a deque of indices with monotonically decreasing values — the front always holds the maximum of the current window. This adds O(k) space but keeps the sliding process O(n).
Another variant: sliding window with hashmap for pattern matching (e.g., find all anagrams in a string). Here the window size is fixed but you need to match character frequency exactly. Use a frequency map and a counter of matched characters to avoid rescanning.
Space complexity varies across patterns. Fixed-size numeric windows can be O(1) — just two integers for sum and max. Dynamic windows with character constraints need O(k) space for frequency map, where k is the number of distinct characters allowed. Monotonic queue windows need O(k) for the deque. Understanding these trade-offs is crucial for memory-constrained environments like embedded systems or real-time trading engines.
When Not to Slide — The Anti-Pattern That Wastes Cycles
You're three rounds deep in an interview, palms sweaty, and the problem involves subarrays. Your brain screams "sliding window!" — and sometimes that instinct is wrong.
Sliding windows only work when the data has a linear, contiguous constraint. The moment you need non-contiguous elements, reordering, or global comparisons, the window breaks. I've watched junior devs waste forty-five minutes forcing a sliding window onto a knapsack variant. Painful.
The real signal is monotonicity — does shrinking the window from the left always preserve the viability of what's on the right? If not, you're fighting the data structure. Use prefix sums, two pointers from opposite ends, or a frequency map with reset logic.
Production lesson: we once tried a sliding window for detecting traffic anomalies across time zones. The window leaked non-contiguous events. Rewrote it with a buffer and index tracking. 300ms became 12ms.
Medium — Where Interviewers Separate the Real Engineers
Easy sliding window problems are warm-ups. Medium problems test whether you can adapt the window shape on the fly. The difference? Constraints that change per element, not per window.
Real pattern: longest substring with at most K distinct characters. Your window expands freely until it violates the distinct count. Then you shrink not by one, but until the violation clears. That's not a fixed increment — it's a state-based shrink.
Another classic: maximum consecutive ones with K flips. Here, the window tracks the count of zeroes. When zeroes exceed K, you move the left pointer until one zero exits the window. The insight? You're not flipping — you're counting. The window itself models the allowable flips.
Production analogy: rate-limiting a microservice endpoint. The window tracks request timestamps. When new request arrives, you drop timestamps older than 1 second. That's not a size window — it's a time-based dynamic window. Exact same logic as substring with K distinct, just with Unix millis instead of characters.
Don't memorize problem variations. Understand why the window moves. Then you can defend it under pressure.
Sliding Window Template: Fixed vs Dynamic Size
The sliding window technique can be categorized into two main types: fixed-size windows and dynamic-size windows. Understanding the template for each is crucial for efficient problem-solving.
Fixed-Size Window Template: - Initialize a window of size k. - Compute the result for the first window. - Slide the window by one element: remove the leftmost element and add the new rightmost element. - Update the result based on the new window.
Example: Given an array and an integer k, find the maximum sum of any contiguous subarray of size k.
Dynamic-Size Window Template: - Use two pointers (left and right) to expand and contract the window. - Expand the right pointer until a condition is violated. - Contract the left pointer until the condition is satisfied again. - Track the optimal result during the process.
Example: Find the longest subarray with sum less than or equal to a target.
Key Differences: - Fixed windows maintain a constant size; dynamic windows adjust based on constraints. - Fixed windows often use a simple loop; dynamic windows require careful pointer management.
Choosing the right template depends on whether the window size is predetermined or variable based on a condition.
Sliding Window with Deque: Maximum/Minimum in Window
When you need to track the maximum or minimum value in a sliding window efficiently, a deque (double-ended queue) is the perfect data structure. It allows O(1) access to the window's extremum and O(n) overall time.
How it works: - Maintain a deque that stores indices of array elements. - For each new element, remove indices from the back that correspond to smaller (for max) or larger (for min) values. - Remove indices from the front that are out of the current window. - The front of the deque always holds the index of the current maximum/minimum.
Example: Given an array and window size k, return an array of maximums for each window.
Algorithm: 1. Initialize an empty deque and result list. 2. For each index i in the array: - Remove indices from back while arr[deque[-1]] <= arr[i] (for max). - Append i to deque. - Remove front index if it's out of window (i - deque[0] >= k). - If i >= k-1, add arr[deque[0]] to result. 3. Return result.
This technique is essential for problems like "Sliding Window Maximum" on LeetCode.
Time Complexity: O(n) — each element is added and removed from deque at most once. Space Complexity: O(k) for the deque.
Sliding Window with Hash Map: Count Occurrences Pattern
When a problem involves counting occurrences of elements within a window (e.g., distinct characters, frequency of items), combining a sliding window with a hash map is a powerful pattern. The hash map stores the count of each element in the current window, enabling O(1) updates and lookups.
Common Use Cases: - Longest substring without repeating characters. - Find all anagrams in a string. - Minimum window substring.
Pattern Template: 1. Use two pointers (left, right) to define the window. 2. Maintain a hash map (or counter) for elements in the window. 3. Expand right pointer, updating the map. 4. When a condition is violated (e.g., duplicate found), shrink from left until condition is restored. 5. Track the optimal result (e.g., maximum length, minimum window).
Example: Longest Substring Without Repeating Characters - Use a hash map to store the last index of each character. - When a character repeats, move left pointer to max(left, last_index + 1). - Update the character's index and compute max length.
Time Complexity: O(n) — each element is visited at most twice. Space Complexity: O(min(m, n)) where m is the size of the character set.
This pattern is essential for string problems involving frequency constraints.
Real-Time Sensor Monitoring Pipeline Delivers Wrong Rolling Averages
- Always synchronize state in multi-threaded sliding window implementations.
- Use thread-safe structures like ConcurrentLinkedDeque or explicit locks.
- Validate sliding window behaviour with a single-threaded test harness before deploying to production streams.
map.size() is your distinct counter — stale keys cause infinite growth.| File | Command / Code | Purpose |
|---|---|---|
| MaxSumFixedWindow.java | public class MaxSumFixedWindow { | Fixed-Size Windows |
| LongestSubstringKDistinct.java | public class LongestSubstringKDistinct { | Dynamic Windows |
| MinSizeSubarraySum.java | public class MinSizeSubarraySum { | Recognising the Pattern Fast |
| StreamSlidingWindow.java | /** | Production-Grade Implementation |
| SlidingWindowMaximum.java | public class SlidingWindowMaximum { | Sliding Window Variants and Space Complexity Considerations |
| AntiPatternCheck.py | def is_valid_sliding_window(arr, condition): | When Not to Slide |
| MaxOnesWithFlips.py | def longest_ones_with_flips(nums, k): | Medium |
| sliding_window_template.py | def max_sum_fixed(arr, k): | Sliding Window Template |
| sliding_window_max_deque.py | from collections import deque | Sliding Window with Deque |
| longest_substring_no_repeat.py | def length_of_longest_substring(s): | Sliding Window with Hash Map |
Key takeaways
Interview Questions on This Topic
Longest Substring with at Most K Distinct Characters: Given a string s and an integer k, return the length of the longest substring of s that contains at most k distinct characters. (LeetCode #340)
map.size() > k, shrink left: decrement count of left char, remove if count becomes 0, increment left. Update max length after shrink. Complexity O(n) time, O(k) space.Frequently Asked Questions
20+ years shipping production code across the stack, with years spent interviewing engineers. Everything here is grounded in real deployments.
That's Coding Patterns. Mark it forged?
8 min read · try the examples if you haven't