Sliding Window: When and How to Use It
Understand the sliding window pattern for solving subarray and substring problems. Includes fixed-size and dynamic window examples.
What is the Sliding Window Pattern?
The sliding window technique is used to perform operations on a specific window size of an array or string. Instead of recalculating from scratch for each window (O(n×k) time), we "slide" the window by one position and update our calculation incrementally (O(n) time).
Think of it like sliding a physical window across a wall - as you move it, you only need to account for what enters and what leaves the window.
When to Use Sliding Window
Consider the sliding window pattern when:
- Finding subarrays or substrings that meet certain criteria
- Maximum/minimum sum of size k subarray
- Longest/shortest substring with certain properties
- Contiguous sequence problems
- Questions mention: "subarray", "substring", "consecutive elements", "window"
Two Types of Sliding Window
1. Fixed-Size Window
The window size is predetermined and constant. Slide it one position at a time.
function maxSumSubarray(arr: number[], k: number): number {
if (arr.length < k) return -1
// Calculate sum of first window
let windowSum = 0
for (let i = 0; i < k; i++) {
windowSum += arr[i]
}
let maxSum = windowSum
// Slide window: remove leftmost, add rightmost
for (let i = k; i < arr.length; i++) {
windowSum = windowSum - arr[i - k] + arr[i]
maxSum = Math.max(maxSum, windowSum)
}
return maxSum
}
// Example: maxSumSubarray([1, 4, 2, 10, 2, 3, 1, 0, 20], 4) → 24
// Window: [10, 2, 3, 9] = 242. Dynamic-Size Window (Variable)
The window expands and contracts based on a condition. Use two pointers:left and right.
function longestSubstringKDistinct(s: string, k: number): number {
const charCount = new Map<string, number>()
let left = 0
let maxLength = 0
for (let right = 0; right < s.length; right++) {
// Expand window: add right character
const rightChar = s[right]
charCount.set(rightChar, (charCount.get(rightChar) || 0) + 1)
// Contract window: remove from left while invalid
while (charCount.size > k) {
const leftChar = s[left]
charCount.set(leftChar, charCount.get(leftChar)! - 1)
if (charCount.get(leftChar) === 0) {
charCount.delete(leftChar)
}
left++
}
// Update result
maxLength = Math.max(maxLength, right - left + 1)
}
return maxLength
}
// Example: longestSubstringKDistinct("araaci", 2) → 4
// Longest substring with ≤ 2 distinct chars: "araa"The Template Pattern
Most dynamic sliding window problems follow this template:
function slidingWindowTemplate(arr: any[]): number {
let left = 0
let result = 0
// Initialize window state (counter, map, sum, etc.)
for (let right = 0; right < arr.length; right++) {
// 1. Add arr[right] to window
// 2. While window is invalid, shrink from left
while (/* window condition violated */) {
// Remove arr[left] from window
left++
}
// 3. Update result with current valid window
result = Math.max(result, right - left + 1)
}
return result
}Common Problems & Solutions
Problem 1: Longest Substring Without Repeating Characters
Question: Find the length of the longest substring without repeating characters.
function lengthOfLongestSubstring(s: string): number {
const charSet = new Set<string>()
let left = 0
let maxLength = 0
for (let right = 0; right < s.length; right++) {
// Shrink window until no duplicates
while (charSet.has(s[right])) {
charSet.delete(s[left])
left++
}
charSet.add(s[right])
maxLength = Math.max(maxLength, right - left + 1)
}
return maxLength
}
// Example: "abcabcbb" → 3 (substring "abc")
// Example: "bbbbb" → 1 (substring "b")Problem 2: Minimum Window Substring
Question: Find the smallest substring in s that contains all characters from t.
function minWindow(s: string, t: string): string {
if (s.length === 0 || t.length === 0) return ""
// Count characters needed
const need = new Map<string, number>()
for (const char of t) {
need.set(char, (need.get(char) || 0) + 1)
}
let left = 0
let right = 0
let formed = 0 // Unique chars in window matching need
const required = need.size
const windowCounts = new Map<string, number>()
// [minLen, left, right]
let ans: [number, number, number] = [Infinity, 0, 0]
while (right < s.length) {
// Expand window
const char = s[right]
windowCounts.set(char, (windowCounts.get(char) || 0) + 1)
if (need.has(char) && windowCounts.get(char) === need.get(char)) {
formed++
}
// Contract window while valid
while (formed === required && left <= right) {
// Update result
if (right - left + 1 < ans[0]) {
ans = [right - left + 1, left, right]
}
// Shrink from left
const leftChar = s[left]
windowCounts.set(leftChar, windowCounts.get(leftChar)! - 1)
if (need.has(leftChar) &&
windowCounts.get(leftChar)! < need.get(leftChar)!) {
formed--
}
left++
}
right++
}
return ans[0] === Infinity ? "" : s.substring(ans[1], ans[2] + 1)
}
// Example: s = "ADOBECODEBANC", t = "ABC" → "BANC"Problem 3: Maximum Average Subarray
Question: Find the contiguous subarray of length k with maximum average.
function findMaxAverage(nums: number[], k: number): number {
// Calculate first window
let sum = 0
for (let i = 0; i < k; i++) {
sum += nums[i]
}
let maxSum = sum
// Slide window
for (let i = k; i < nums.length; i++) {
sum = sum - nums[i - k] + nums[i]
maxSum = Math.max(maxSum, sum)
}
return maxSum / k
}
// Example: [1,12,-5,-6,50,3], k=4 → 12.75
// Subarray: [12,-5,-6,50]Time & Space Complexity
Fixed Window:
Time: O(n) - Single pass through array
Space: O(1) - Only storing window sum/state
Dynamic Window:
Time: O(n) - Each element visited at most twice (right pointer adds, left pointer removes)
Space: O(k) - Where k is the size of character set or window tracking structure
Pro Tips
- Right pointer always moves forward - Never goes backwards
- Left pointer catches up - Only moves when window is invalid
- Use hash map for character/element frequency tracking
- Check edge cases: Empty array, k larger than array length, k=1
- Update result after checking validity - Not during shrinking
Common Mistakes
- Moving both pointers in nested loops → O(n²) time
- Forgetting to remove left element when shrinking window
- Updating result before window is valid
- Using wrong loop condition (should be
right < n)
Practice Problems
Test your understanding with these problems:
- Easy: Maximum Average Subarray, Contains Duplicate II
- Medium: Longest Substring Without Repeating Characters, Max Consecutive Ones III, Fruit Into Baskets
- Hard: Minimum Window Substring, Sliding Window Maximum
Master Sliding Window with HireReady
Practice 50+ sliding window problems with our adaptive learning system. Get instant feedback and track your progress over time.
Start Free Practice →Continue Learning
- Two Pointers Pattern Explained - A related technique often used together with sliding window
- Hash Maps: When and Why - Essential for tracking window contents efficiently
- Big O Notation Explained - Understand the O(n) complexity of sliding window
- Start Practicing - Apply sliding window to real interview problems
Article Details
This guide is part of HireReady's interview prep library and is maintained to reflect current hiring practices.
Further Reading
Keep Reading
Trie Data Structure: Complete Interview Guide
Master the trie (prefix tree) for solving autocomplete, spell checking, and word search problems. Learn implementation, variations, and common interview patterns.
Read moreStack Pattern: Complete Interview Guide
Master stack patterns for coding interviews. Learn matching brackets, monotonic stack, expression evaluation, and common LeetCode problems.
Read moreBig O Notation Explained
Complete guide to Big O notation, algorithmic complexity, and performance analysis. Learn to calculate time and space complexity from code with real examples.
Read more