Sliding Window Pattern
1. Fixed-size Window Techniques
| Technique | Pattern | Use Case | Time |
|---|---|---|---|
| Fixed Window | sum = arr[0...k-1]; slide right |
Calculate sum/avg of k consecutive elements | O(n) |
| Sliding Average | avg = sum / k |
Moving average calculations, smoothing data | O(n) |
| Window Update | sum += arr[i] - arr[i-k] |
Add new element, remove old element | O(1) |
| Max in Window | deque for max tracking |
Maximum element in each window of size k | O(n) |
Example: Maximum sum of k consecutive elements
function maxSumFixedWindow(arr, k) {
if (arr.length < k) return null;
// Calculate first window sum
let windowSum = 0;
for (let i = 0; i < k; i++) {
windowSum += arr[i];
}
let maxSum = windowSum;
// Slide window: add next, remove first
for (let i = k; i < arr.length; i++) {
windowSum += arr[i] - arr[i - k];
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
// Example usage
const arr = [2, 1, 5, 1, 3, 2];
console.log(maxSumFixedWindow(arr, 3)); // Output: 9 (5+1+3)
2. Variable-size Window Optimization
| Pattern | Strategy | When to Use | Complexity |
|---|---|---|---|
| Expand-Shrink | Expand right until condition fails, then shrink left | Find smallest/largest window meeting criteria | O(n) |
| Two Pointer | Left and right pointers move independently | Subarray sum equals target, substring problems | O(n) |
| HashMap Tracking | Track frequency/count in current window | Distinct elements, character frequency | O(n) |
| Condition Check | Validate window on each expansion/shrink | Complex constraints validation | O(n) |
Example: Smallest subarray with sum ≥ target
function minSubArrayLen(target, nums) {
let left = 0, sum = 0;
let minLen = Infinity;
for (let right = 0; right < nums.length; right++) {
sum += nums[right]; // Expand window
// Shrink window while condition met
while (sum >= target) {
minLen = Math.min(minLen, right - left + 1);
sum -= nums[left];
left++;
}
}
return minLen === Infinity ? 0 : minLen;
}
// Example
console.log(minSubArrayLen(7, [2,3,1,2,4,3])); // Output: 2 ([4,3])
3. Maximum/Minimum Subarray Problems
| Problem Type | Approach | Data Structure | Example |
|---|---|---|---|
| Max Sum Subarray | Kadane's algorithm or sliding window | Variables for current/max sum | Maximum profit, maximum subarray sum |
| Min/Max in Window | Monotonic deque | Deque storing indices | Sliding window maximum/minimum |
| Product Maximum | Track both max and min (negative numbers) | Two variables for max/min product | Maximum product subarray |
| Fixed Length Max | Fixed window with running max/min | Window sum + comparison | Max average subarray of length k |
Example: Sliding Window Maximum
function maxSlidingWindow(nums, k) {
const result = [];
const deque = []; // Store indices
for (let i = 0; i < nums.length; i++) {
// Remove indices outside window
while (deque.length &&
deque[0] <= i - k) {
deque.shift();
}
// Remove smaller elements
while (deque.length &&
nums[deque[deque.length-1]] < nums[i]) {
deque.pop();
}
deque.push(i);
if (i >= k - 1) {
result.push(nums[deque[0]]);
}
}
return result;
}
Example: Maximum Product Subarray
function maxProduct(nums) {
let maxProd = nums[0];
let curMax = nums[0];
let curMin = nums[0];
for (let i = 1; i < nums.length; i++) {
const num = nums[i];
// Swap if negative
if (num < 0) {
[curMax, curMin] = [curMin, curMax];
}
curMax = Math.max(num, curMax * num);
curMin = Math.min(num, curMin * num);
maxProd = Math.max(maxProd, curMax);
}
return maxProd;
}
4. Longest Substring Without Repeating Characters
| Pattern | Key Technique | Tracking Method | Common Problems |
|---|---|---|---|
| Unique Characters | HashMap/Set for character tracking | Store last seen index of each character | Longest substring without repeating chars |
| K Distinct Elements | Expand until k+1 distinct, then shrink | HashMap with character frequency | Longest substring with k distinct chars |
| Character Replacement | Track most frequent + replacement count | Frequency map + max frequency variable | Longest repeating char replacement |
| Anagram Window | Character frequency matching | Two frequency maps comparison | Find all anagrams in string |
Example: Longest substring without repeating characters
function lengthOfLongestSubstring(s) {
const charMap = new Map();
let left = 0, maxLen = 0;
for (let right = 0; right < s.length; right++) {
const char = s[right];
// If duplicate found, move left pointer
if (charMap.has(char)) {
left = Math.max(left, charMap.get(char) + 1);
}
charMap.set(char, right);
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
// Example
console.log(lengthOfLongestSubstring("abcabcbb")); // Output: 3 ("abc")
Example: Longest substring with k distinct characters
function lengthOfLongestSubstringKDistinct(s, k) {
const charCount = new Map();
let left = 0, maxLen = 0;
for (let right = 0; right < s.length; right++) {
const char = s[right];
charCount.set(char, (charCount.get(char) || 0) + 1);
// Shrink window if more than k distinct
while (charCount.size > k) {
const leftChar = s[left];
charCount.set(leftChar, charCount.get(leftChar) - 1);
if (charCount.get(leftChar) === 0) {
charCount.delete(leftChar);
}
left++;
}
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
5. Two-pointer Sliding Window Hybrid Approach
| Variant | Pointer Movement | Use Case | Key Insight |
|---|---|---|---|
| Same Direction | Both pointers move left to right | Variable window size problems | Window expands/shrinks dynamically |
| Opposite Direction | Left moves right, right moves left | Palindrome check, two sum in sorted array | Converge towards middle or target |
| Fast-Slow Pattern | One pointer moves faster than other | Cycle detection, middle element | Speed differential reveals patterns |
| Partitioning | One pointer scans, other marks boundary | Dutch national flag, partition array | Maintain invariant between pointers |
Example: Container with most water (opposite direction)
function maxArea(height) {
let left = 0, right = height.length - 1;
let maxArea = 0;
while (left < right) {
const width = right - left;
const minHeight = Math.min(height[left], height[right]);
const area = width * minHeight;
maxArea = Math.max(maxArea, area);
// Move pointer with smaller height
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return maxArea;
}
6. Time Complexity O(n) Analysis
| Aspect | Analysis | Explanation |
|---|---|---|
| Single Pass | O(n) |
Each element visited at most once by right pointer |
| Left Pointer Movement | O(n) total |
Left pointer moves at most n times across entire execution |
| Combined Movement | O(2n) = O(n) |
Both pointers together traverse array once |
| Space Complexity | O(1) to O(k) |
O(1) for counters, O(k) for HashMap with k unique elements |
Note: Sliding window achieves O(n) time by ensuring each element is processed at most twice - once when entering window (right pointer) and once when leaving (left pointer). This is superior to naive nested loops O(n²).
Sliding Window Pattern Summary
- Fixed Window: Calculate initial sum, slide by adding/removing elements
- Variable Window: Expand until condition breaks, shrink until valid
- Template: Use HashMap for tracking, two pointers for boundaries
- Optimization: Amortized O(n) - each element touched maximum twice
- Common Mistakes: Off-by-one errors, not updating window state correctly
Warning: Always verify window validity before updating result. Ensure left pointer doesn't exceed right pointer. Handle edge cases: empty array, k > array length, negative numbers in product problems.