Sliding Window Algorithm: Fixed & Dynamic Window Strategies
Sliding Window Algorithm: Fixed & Dynamic Window Strategies
The Sliding Window Algorithm is a sub-array and sub-string optimization technique. Instead of recalculating contiguous segments from scratch using nested loops ($O(n^2)$), the algorithm maintains a moving "window" that slides across the sequence, updating the internal state incrementally in $O(n)$ linear time.
1. Real-World Analogy: The Train Window
Imagine you are riding a train through the countryside, looking out through a small rectangular window:
- As the train moves forward 1 meter, you do not need to rediscover the entire landscape.
- One tree enters your field of view from the right, and one tree leaves your field of view from the left.
- The remaining scenery inside the window stays identical! This is the essence of sliding window: Add incoming element on the right, subtract outgoing element on the left.
2. The Two Window Paradigms
Type 1: Fixed-Size Window ($K$)
The size of the window is strictly constant (e.g. "Find maximum sum of any contiguous subarray of length $K$").
- Advance
rightpointer until window size equals $K$. - At each subsequent step: add
arr[right], subtractarr[left], and increment both pointers (left++,right++).
Type 2: Dynamic (Variable-Size) Window
The window size expands and shrinks dynamically to satisfy a constraint (e.g. "Find the longest substring without repeating characters", "Smallest subarray with sum $\ge S$").
- Expand
rightpointer to include elements and update state. - While the window constraint is violated, shrink the window from the left (
left++) until valid again. - Record the maximum/minimum window length at valid states.
3. Fixed Window Implementation: Max Subarray Sum of Size $K$
Python 3:
Modern JavaScript / TypeScript:
4. Dynamic Window: Longest Substring Without Repeating Characters
Given a string s, find the length of the longest substring without duplicate characters:
Python 3:
5. Trace Table: s = "abcabcbb"
right | char | left | Window Substring | Action | max_len |
|---|---|---|---|---|---|
| 0 | 'a' | 0 | "a" | Map: {a:0} | 1 |
| 1 | 'b' | 0 | "ab" | Map: {a:0, b:1} | 2 |
| 2 | 'c' | 0 | "abc" | Map: {a:0, b:1, c:2} | 3 |
| 3 | 'a' | 1 | "bca" | Duplicate 'a' seen at 0 $\to$ left = 0 + 1 = 1 | 3 |
| 4 | 'b' | 2 | "cab" | Duplicate 'b' seen at 1 $\to$ left = 1 + 1 = 2 | 3 |
| 5 | 'c' | 3 | "abc" | Duplicate 'c' seen at 2 $\to$ left = 2 + 1 = 3 | 3 |
| 6 | 'b' | 5 | "b" | Duplicate 'b' seen at 4 $\to$ left = 4 + 1 = 5 | 3 |
| 7 | 'b' | 7 | "b" | Duplicate 'b' seen at 6 $\to$ left = 6 + 1 = 7 | 3 |
Result: Maximum length is 3 ("abc"), achieved in single-pass $O(n)$ time!
Multiple Choice Questions
left pointer advance?left and right pointers only move forward from 0 to $n$, why is the total time complexity $O(n)$ even if there is a while loop nested inside a for loop?Prefix Sums & Difference Arrays for Constant-Time Range Queries
Continue learning with hands-on practice, examples, and exercises in the upcoming topic.
Related Lessons
Practice Quiz
Test your understanding of this lesson with 5 questions. Each question has one correct answer.