Sliding window is a technique where you maintain a contiguous subset (window) of elements and slide it through the data structure. The window can expand or contract based on problem constraints.Key Insight: Instead of recalculating from scratch for each position, maintain state as the window moves.
The standard sliding window pattern from the source code:
int n = any.size();int start = 0, end = 0;map<int, int> counter;int ans = 0;while(end < n) { // Add current element to window counter[any[end]]++; // Shrink window while condition is violated while(condition(start, end) && start <= end) { counter[any[start]]--; process_logic1(start, end); start++; } // Process current window process_logic2(start, end); ans = max(ans, end - start + 1); end++;}
Example 1: Longest Substring Without Repeating Characters
Find the length of the longest substring without repeating characters.
int lengthOfLongestSubstring(string s) { int n = s.length(); int start = 0, end = 0; unordered_map<char, int> counter; int maxLen = 0; while(end < n) { // Add current character to window counter[s[end]]++; // Shrink window if we have duplicates while(counter[s[end]] > 1 && start <= end) { counter[s[start]]--; if(counter[s[start]] == 0) { counter.erase(s[start]); } start++; } // Update maximum length maxLen = max(maxLen, end - start + 1); end++; } return maxLen;}// Example usagestring s = "abcabcbb";int result = lengthOfLongestSubstring(s);// Result: 3 ("abc")
Fixed-size window: Find maximum sum of any subarray of size k.
int maxSumSubarray(vector<int>& arr, int k) { if(arr.size() < k) return -1; int n = arr.size(); int windowSum = 0; // Calculate sum of first window for(int i = 0; i < k; i++) { windowSum += arr[i]; } int maxSum = windowSum; // Slide the window for(int end = k; end < n; end++) { // Add new element and remove leftmost element windowSum += arr[end] - arr[end - k]; maxSum = max(maxSum, windowSum); } return maxSum;}// Example usagevector<int> arr = {2, 1, 5, 1, 3, 2};int k = 3;int result = maxSumSubarray(arr, k);// Result: 9 (subarray [5, 1, 3])
Example 5: Count Subarrays with K Different Integers
int subarraysWithAtMostK(vector<int>& arr, int k) { int n = arr.size(); int start = 0, end = 0; unordered_map<int, int> counter; int count = 0; while(end < n) { counter[arr[end]]++; // Shrink while we have more than k distinct elements while(counter.size() > k && start <= end) { counter[arr[start]]--; if(counter[arr[start]] == 0) { counter.erase(arr[start]); } start++; } // All subarrays ending at 'end' with start in [start, end] count += end - start + 1; end++; } return count;}int subarraysWithKDistinct(vector<int>& arr, int k) { // Exactly k = At most k - At most (k-1) return subarraysWithAtMostK(arr, k) - subarraysWithAtMostK(arr, k - 1);}// Example usagevector<int> arr = {1, 2, 1, 2, 3};int k = 2;int result = subarraysWithKDistinct(arr, k);// Result: 7
k is the size of the character set or distinct elements
Why O(n)? Although there’s a nested while loop, each element is added once (by end++) and removed at most once (by start++), giving amortized O(n) time.