Sliding Window Algorithm
The Sliding Window technique is one of the most powerful patterns in DSA. It converts an O(nΒ²) brute-force approach into an elegant O(n) solution for problems involving contiguous subarrays or substrings.
π§ Core Ideaβ
Instead of recalculating from scratch for every subarray, we maintain a window and slide it across the array β adding one element on the right and removing one on the left.
Array: [ 2, 1, 5, 1, 3, 2 ] K = 3
Window 1: [2, 1, 5] β sum = 8
β slide
Window 2: [1, 5, 1] β sum = 7 (remove 2, add 1)
β slide
Window 3: [5, 1, 3] β sum = 9 (remove 1, add 3) β MAX
β slide
Window 4: [1, 3, 2] β sum = 6 (remove 5, add 2)
ποΈ Types of Sliding Windowβ
| Type | Window Size | Use When |
|---|---|---|
| Fixed Window | Constant (K) | Problem gives a fixed size K |
| Variable Window | Grows & shrinks | Find longest/shortest satisfying a condition |
π Type 1: Fixed Size Sliding Windowβ
When to Useβ
- "Find max/min sum of subarray of size K"
- "Find average of every subarray of size K"
- The window size is given directly in the problem
Visual Diagramβ
Problem: Max sum subarray of size K=3
Array = [2, 1, 5, 1, 3, 2]
STEP 1: Build first window
βββββββββββββββββββ
β 2 β 1 β 5 β 1 3 2
ββββββββ βββββββββββ
sum = 8 max = 8
STEP 2: Slide β remove left, add right
βββββββββββββββββββ
2 β 1 β 5 β 1 β 3 2
βββββββββββββββββββ
sum = 8 - 2 + 1 = 7 max = 8
STEP 3: Slide again
βββββββββββββββββββ
2 1 β 5 β 1 β 3 β 2
βββββββββββββββββββ
sum = 7 - 1 + 3 = 9 max = 9 β
STEP 4: Slide again
βββββββββββββββββββ
2 1 5 β 1 β 3 β 2 β
βββββββββββββββββββ
sum = 9 - 5 + 2 = 6 max = 9
Answer: 9
Code Templateβ
- Python
- Java
- C++
def max_sum_subarray(arr, k):
n = len(arr)
if n < k:
return -1
# Step 1: Build first window
window_sum = sum(arr[:k])
max_sum = window_sum
# Step 2: Slide the window
for i in range(k, n):
window_sum += arr[i] # Add incoming element (right)
window_sum -= arr[i - k] # Remove outgoing element (left)
max_sum = max(max_sum, window_sum)
return max_sum
# Example
arr = [2, 1, 5, 1, 3, 2]
print(max_sum_subarray(arr, 3)) # Output: 9
public class SlidingWindow {
public static long maxSumSubarray(int[] arr, int k) {
int n = arr.length;
if (n < k) return -1;
// Step 1: Build first window
long windowSum = 0;
for (int i = 0; i < k; i++) {
windowSum += arr[i];
}
long maxSum = windowSum;
// Step 2: Slide the window
for (int i = k; i < n; i++) {
windowSum += arr[i]; // Add incoming element (right)
windowSum -= arr[i - k]; // Remove outgoing element (left)
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
public static void main(String[] args) {
int[] arr = {2, 1, 5, 1, 3, 2};
System.out.println(maxSumSubarray(arr, 3)); // Output: 9
}
}
#include <bits/stdc++.h>
using namespace std;
long long maxSumSubarray(vector<int>& arr, int k) {
int n = arr.size();
if (n < k) return -1;
// Step 1: Build first window
long long windowSum = 0;
for (int i = 0; i < k; i++) {
windowSum += arr[i];
}
long long maxSum = windowSum;
// Step 2: Slide the window
for (int i = k; i < n; i++) {
windowSum += arr[i]; // Add incoming element (right)
windowSum -= arr[i - k]; // Remove outgoing element (left)
maxSum = max(maxSum, windowSum);
}
return maxSum;
}
int main() {
vector<int> arr = {2, 1, 5, 1, 3, 2};
cout << maxSumSubarray(arr, 3) << endl; // Output: 9
return 0;
}
Time Complexity: O(n) Β |Β Space Complexity: O(1)
π Type 2: Variable Size Sliding Windowβ
When to Useβ
- "Find the longest substring/subarray satisfying a condition"
- "Find the smallest subarray with sum β₯ target"
- Window size is not fixed β it expands and shrinks based on a condition
How it Worksβ
Two pointers: LEFT and RIGHT
- RIGHT expands the window (moves forward always)
- LEFT shrinks the window (moves forward when condition is violated)
LEFT RIGHT
β β
[ a b c d e f g ]
ββββwindowβββ
Classic Problem: Longest Substring Without Repeating Charactersβ
Input: s = "a b c a b c b b"
0 1 2 3 4 5 6 7
right=0: window="a" no repeat β length=1
right=1: window="ab" no repeat β length=2
right=2: window="abc" no repeat β length=3
right=3: 'a' REPEATS!
β shrink: remove s[left]='a', left=1
β window="bca" no repeat β length=3
right=4: 'b' REPEATS!
β shrink: remove s[left]='b', left=2
β window="cab" no repeat β length=3
right=5: 'c' REPEATS!
β shrink: remove s[left]='c', left=3
β window="abc" no repeat β length=3
right=6: 'b' REPEATS!
β shrink until valid: left=5
β window="cb" length=2
right=7: 'b' REPEATS!
β shrink: left=7
β window="b" length=1
β
Answer: 3 ("abc")
Code Templateβ
- Python
- Java
- C++
def longest_substring_no_repeat(s):
char_map = {} # stores char β last seen index
left = 0
max_length = 0
for right in range(len(s)):
# If char is already in window, shrink from left
if s[right] in char_map and char_map[s[right]] >= left:
left = char_map[s[right]] + 1
# Update last seen position
char_map[s[right]] = right
# Update max length
max_length = max(max_length, right - left + 1)
return max_length
# Example
print(longest_substring_no_repeat("abcabcbb")) # Output: 3
print(longest_substring_no_repeat("pwwkew")) # Output: 3
import java.util.HashMap;
public class SlidingWindow {
public static int lengthOfLongestSubstring(String s) {
HashMap<Character, Integer> charMap = new HashMap<>();
int left = 0;
int maxLength = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
// If char is already in window, shrink from left
Integer lastSeen = charMap.get(c);
if (lastSeen != null && lastSeen >= left) {
left = lastSeen + 1;
}
// Update last seen position
charMap.put(c, right);
// Update max length
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
}
public static void main(String[] args) {
System.out.println(lengthOfLongestSubstring("abcabcbb")); // Output: 3
}
}
#include <bits/stdc++.h>
using namespace std;
int lengthOfLongestSubstring(string s) {
unordered_map<char, int> charMap;
int left = 0;
int maxLength = 0;
int n = s.size();
for (int right = 0; right < n; right++) {
auto it = charMap.find(s[right]);
if (it != charMap.end() && it->second >= left) {
left = it->second + 1;
}
// Update last seen position
charMap[s[right]] = right;
// Update max length
maxLength = max(maxLength, right - left + 1);
}
return maxLength;
}
int main() {
cout << lengthOfLongestSubstring("abcabcbb") << endl; // Output: 3
return 0;
}
Time Complexity: O(n) Β |Β Space Complexity: O(k) where k = unique characters
β‘ Brute Force vs Sliding Windowβ
Problem: Max sum subarray of size K=3
Array = [2, 1, 5, 1, 3, 2]
β BRUTE FORCE β O(nΒ²)
Window [0..2]: 2+1+5 = 8 (3 additions)
Window [1..3]: 1+5+1 = 7 (3 additions)
Window [2..4]: 5+1+3 = 9 (3 additions)
Window [3..5]: 1+3+2 = 6 (3 additions)
Total: 12 operations
β
SLIDING WINDOW β O(n)
Window [0..2]: 2+1+5 = 8 (3 additions for first window)
Window [1..3]: 8 - 2 + 1 = 7 (1 subtraction + 1 addition)
Window [2..4]: 7 - 1 + 3 = 9 (1 subtraction + 1 addition)
Window [3..5]: 9 - 5 + 2 = 6 (1 subtraction + 1 addition)
Total: 9 operations β
Faster!
π Complexity Summaryβ
| Problem Type | Time | Space |
|---|---|---|
| Fixed window (sum, avg) | O(n) | O(1) |
| Variable window (longest substring) | O(n) | O(k) |
| Variable window (smallest subarray) | O(n) | O(1) |
β Common Mistakesβ
- Forgetting to shrink the window β Always move
leftforward when your condition is violated. - Using nested loops β If you see O(nΒ²) on a subarray problem, think Sliding Window.
- Wrong window size formula β Current window size is always
right - left + 1. - Not handling edge cases β Empty array, K larger than array length.
- Reinitializing variables inside the loop β
max_sum,leftshould be declared outside.
ποΈ Practice Problemsβ
| # | Problem | Type | Difficulty |
|---|---|---|---|
| 1 | Maximum Sum Subarray of Size K | Fixed | π’ Easy |
| 2 | Average of Subarrays of Size K | Fixed | π’ Easy |
| 3 | Longest Substring Without Repeating Characters | Variable | π‘ Medium |
| 4 | Minimum Size Subarray Sum | Variable | π‘ Medium |
| 5 | Fruits Into Baskets | Variable | π‘ Medium |
| 6 | Longest Repeating Character Replacement | Variable | π‘ Medium |
| 7 | Permutation in String | Fixed | π‘ Medium |
| 8 | Minimum Window Substring | Variable | π΄ Hard |
| 9 | Sliding Window Maximum | Fixed + Deque | π΄ Hard |