The Sliding Window Pattern is one of the most foundational and frequently tested algorithmic design patterns in technical interviews. Top-tier engineering companies favor these problems because naive, brute-force iterations often cost $O(N^2)$ or $O(N^3)$ in runtime performance. By applying a sliding window strategy, you can optimize your solution to execute in efficient linear time: $O(N)$ or linearithmic time: $O(N \log N)$.
What is a Sliding Window?
Imagine a window of fixed or dynamic size that glides across a contiguous sequential structure (like an array or string). Instead of entirely recalculating values for every sub-segment from scratch, the window shifts positions by performing fractional, constant-time operations: evicting the leftmost element that falls out of bounds and incorporating the newest rightmost element entering the frame.
Consider an array with a window size of $K = 3$ moving from left to right:
Array: [1, 2, 3, 4, 5, 6]
Window Position 1: [1 2 3] 4 5 6
Window Position 2: 1 [2 3 4] 5 6
Window Position 3: 1 2 [3 4 5] 6
Window Position 4: 1 2 3 [4 5 6]
Why Use the Sliding Window Pattern?
Suppose you are tasked with finding the maximum sum of a contiguous subarray of size 3 within an array: [1, 2, 3, 4, 5, 6].
A brute-force strategy evaluates every individual subarray window comprehensively:
1 + 2 + 3 = 62 + 3 + 4 = 93 + 4 + 5 = 124 + 5 + 6 = 15
Notice that we iteratively sum overlapping inner values over and over again. This yields a processing complexity of $O(N \times K)$, scaling poorly to quadratic $O(N^2)$ as bounds widen. Alternatively, a sliding window preserves the state of the previous window, drops the trailing value, and includes the leading value. This reduces computation costs down to a deterministic $O(N)$ runtime.
Types of Sliding Window
Sliding window problems fall into two distinct execution strategies based on bounds characteristics:
1. Fixed-Size Window
The total length of the window frame remains entirely constant throughout the entire runtime traversal. Examples include computing the maximum sum of $K$ elements or extracting the average of all sub-arrays of length $K$.
General Code Paradigm:
int left = 0;
for (int right = 0; right < n; right++) {
// 1. Incorporate right element into operational state
add_element(arr[right]);
// 2. Maintain structural size compliance
if ((right - left + 1) > k) {
remove_element(arr[left]);
left++;
}
// 3. Process valid frame output here
}
2. Variable-Size Window
The boundaries of the window dynamically expand or contract based on an evaluation condition. Examples include searching for the longest unique substring or the smallest subarray exceeding a target total.
General Code Paradigm:
int left = 0;
for (int right = 0; right < n; right++) {
add_element(arr[right]);
// Shrink bounds dynamically until conditional invariants are restored
while (condition_is_violated()) {
remove_element(arr[left]);
left++;
}
// Process output or track structural maximums
}
Core Problems Deep Dive
Problem 1: Maximum Sum Subarray of Size K (Fixed Window)
Problem Statement: Given an array [2, 1, 5, 1, 3, 2] and $K = 3$, identify the maximum possible sum across all valid configurations of size 3.
Brute Force Approach
An inner nested loop computes sums for all sequential collections starting from each array index:
for (int i = 0; i <= n - k; i++) {
int current_sum = 0;
for (int j = i; j < i + k; j++) {
current_sum += arr[j];
}
// Track maximum sum (Time Complexity: O(N * K))
}
Sliding Window Optimization
Compute an initial base window sum, then slide the frame systematically across the array by adding the element at right and subtracting the element at right - K.
Dry Run Execution:
- Initial Window (Indices 0 to 2):
2 + 1 + 5 = 8→maxSum = 8 - Slide 1 (Drop 2, Add 1):
8 - 2 + 1 = 7→maxSum = 8 - Slide 2 (Drop 1, Add 3):
7 - 1 + 3 = 9→maxSum = 9 - Slide 3 (Drop 5, Add 2):
9 - 5 + 2 = 6→maxSum = 9
Result: 9
C Code Implementation:
#include <stdio.h>
int main() {
int arr[] = {2, 1, 5, 1, 3, 2};
int n = sizeof(arr) / sizeof(arr[0]);
int k = 3;
int windowSum = 0;
for (int i = 0; i < k; i++) {
windowSum += arr[i];
}
int maxSum = windowSum;
for (int i = k; i < n; i++) {
windowSum = windowSum - arr[i - k] + arr[i];
if (windowSum > maxSum) {
maxSum = windowSum;
}
}
printf("Maximum Sum = %d\n", maxSum); // Output: 9
return 0;
}
Complexity: Time: $O(N)$ | Space: $O(1)$
Problem 2: Longest Unique Substring (Variable Window)
Problem Statement: Given a string "abcabcbb", isolate the length of the longest distinct contiguous substring without repeating characters.
Note: Substring components must remain entirely continuous (e.g., "abc" is a valid substring of "abcdef", whereas "ace" is not).
Optimized Strategy
Use independent left and right boundaries alongside a frequency hash-map tracker. Expand the right boundary to ingest characters. If a frequency count exceeds 1, systematically slide the left boundary forward and decrement counts until the duplication conflict resolves.
C Code Implementation:
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "abcabcbb";
int freq[256] = {0};
int left = 0, maxLen = 0;
int n = strlen(str);
for (int right = 0; right < n; right++) {
freq[(unsigned char)str[right]]++;
while (freq[(unsigned char)str[right]] > 1) {
freq[(unsigned char)str[left]]--;
left++;
}
int currentLen = right - left + 1;
if (currentLen > maxLen) {
maxLen = currentLen;
}
}
printf("Longest Length = %d\n", maxLen); // Output: 3 ("abc")
return 0;
}
Complexity Analysis: Although it contains nested loops, both the left and right pointers traverse the sequential space at most once. This ensures a strict linear performance runtime profile of $O(N)$ with an absolute constant space layout of $O(1)$ based on the fixed ASCII spectrum table (256 slots).
Essential Interview Practice Set
1. Longest Subarray with Sum K
Problem: Given [1, 2, 1, 1, 1] and target $K = 3$, look for the maximum length of a valid matching sequence.
#include <stdio.h>
int main() {
int arr[] = {1, 2, 1, 1, 1};
int n = 5, k = 3;
int left = 0, sum = 0, maxLen = 0;
for (int right = 0; right < n; right++) {
sum += arr[right];
while (sum > k) {
sum -= arr[left];
left++;
}
if (sum == k) {
int len = right - left + 1;
if (len > maxLen) maxLen = len;
}
}
printf("Longest Length = %d\n", maxLen); // Output: 3 (Subarray: [1,1,1])
return 0;
}
2. Maximum Consecutive Ones
Problem: Identify the maximum continuous streak of 1s within a binary stream [1, 1, 0, 1, 1, 1, 0, 1].
#include <stdio.h>
int main() {
int arr[] = {1, 1, 0, 1, 1, 1, 0, 1};
int n = 8, current = 0, maxCount = 0;
for (int i = 0; i < n; i++) {
if (arr[i] == 1) {
current++;
if (current > maxCount) maxCount = current;
} else {
current = 0;
}
}
printf("Max Consecutive Ones = %d\n", maxCount); // Output: 3
return 0;
}
3. Minimum Size Subarray Sum
Problem: Given [2, 3, 1, 2, 4, 3] and a goal threshold of 7, find the minimal length where total sum $\ge \text{target}$.
#include <stdio.h>
#include <limits.h>
int main() {
int arr[] = {2, 3, 1, 2, 4, 3};
int n = 6, target = 7;
int left = 0, sum = 0, minLen = INT_MAX;
for (int right = 0; right < n; right++) {
sum += arr[right];
while (sum >= target) {
int len = right - left + 1;
if (len < minLen) minLen = len;
sum -= arr[left];
left++;
}
}
printf("Minimum Length = %d\n", minLen == INT_MAX ? 0 : minLen); // Output: 2 ([4, 3])
return 0;
}
4. Longest Repeating Character Replacement
Problem: Given "AABABBA" and operations limit $K = 1$, find the maximum string sequence achievable after replacing a single character.
Rule: The window configuration is valid if: $\text{windowSize} - \text{maxFrequency} \le K$.
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "AABABBA";
int k = 1, freq[26] = {0}, left = 0, maxFreq = 0, result = 0;
int n = strlen(str);
for (int right = 0; right < n; right++) {
freq[str[right] - 'A']++;
if (freq[str[right] - 'A'] > maxFreq) maxFreq = freq[str[right] - 'A'];
while ((right - left + 1) - maxFreq > k) {
freq[str[left] - 'A']--;
left++;
}
int len = right - left + 1;
if (len > result) result = len;
}
printf("Max Length = %d\n", result); // Output: 4
return 0;
}
5. Fruit Into Baskets
Problem: Collect continuous elements from an array [1, 2, 1, 2, 3] given a strict structural constraint of containing at most 2 distinct integers.
#include <stdio.h>
int main() {
int arr[] = {1, 2, 1, 2, 3};
int n = 5, freq[100] = {0}, left = 0, distinct = 0, answer = 0;
for (int right = 0; right < n; right++) {
if (freq[arr[right]] == 0) distinct++;
freq[arr[right]]++;
while (distinct > 2) {
freq[arr[left]]--;
if (freq[arr[left]] == 0) distinct--;
left++;
}
int len = right - left + 1;
if (len > answer) answer = len;
}
printf("Max Fruit Collected = %d\n", answer); // Output: 4
return 0;
}
6. Minimum Window Substring
Problem: For input String "ADOBECODEBANC" and pattern match sequence "ABC", isolate the smallest continuous span containing all required search targets.
Strategy Note: This highly advanced task uses a tracking counter structure paired with an active frequency array to contract boundaries eagerly while verifying character requirements. Runtime is linear $O(N)$.
7. Sliding Window Maximum
Problem: Extract the maximum value for each sliding sub-block configuration of size $K$ across an array.
Strategy Note: Instead of simple parameters, this is optimized via a Monotonic Deque architecture keeping elements structured in sorted decreasing order. This avoids re-scanning values and handles updates in $O(1)$ amortized runtime.
8. Find All Anagrams / Permutations in a String
Problem: Find all matching sub-segments inside text "cbaebabacd" that match character patterns found in "abc".
#include <stdio.h>
#include <string.h>
int main() {
char text[] = "cbaebabacd";
char pattern[] = "abc";
int freqP[26] = {0}, freqW[26] = {0};
int pLen = strlen(pattern), tLen = strlen(text), count = 0;
if (pLen > tLen) return 0;
for (int i = 0; i < pLen; i++) {
freqP[pattern[i] - 'a']++;
freqW[text[i] - 'a']++;
}
for (int i = pLen; i <= tLen; i++) {
int same = 1;
for (int j = 0; j < 26; j++) {
if (freqP[j] != freqW[j]) { same = 0; break; }
}
if (same) count++;
if (i < tLen) {
freqW[text[i] - 'a']++;
freqW[text[i - pLen] - 'a']--;
}
}
printf("Total Anagram Occurrences = %d\n", count); // Output: 2
return 0;
}
Pattern Recognition Strategy Guide
| If the Problem Mentions... | Window Type Strategy |
|---|---|
| "Subarray of precise size K" / "Average of K size windows" | Fixed-Size Sliding Window |
| "Find continuous anagram occurrences / string permutations" | Fixed-Size Sliding Window |
| "Longest substring without repeating entities" | Variable-Size Sliding Window |
| "Minimum frame span where cumulative value meets target" | Variable-Size Sliding Window |
| "At most / Exactly K matching structural variations" | Variable-Size Sliding Window |
Pattern Blueprint Summary
Always remember the Golden Template when implementing solutions on whiteboard sessions:
// The Golden Sliding Window Template
for (int right = 0; right < total_elements; right++) {
incorporate_element(arr[right]);
while (window_state_is_invalid()) {
evict_element(arr[left]);
left++;
}
track_and_update_optimal_answer(right - left + 1);
}
Frequently Asked Questions (FAQs)
While Sliding Window uses two pointers, it specifically targets contiguous subarrays or substrings where the elements enclosed between the pointers form the state. The standard Two-Pointer technique often operates from opposite ends of a sorted array to find pairs, without focusing on the elements in between.
Even though there is a loop inside a loop, the left pointer only moves forward and never backtracks. Across the entire array traversal, the left pointer can increment at most $N$ times total. This makes the amortized time complexity linear, or $O(2N)$, which simplifies to $O(N)$.
When computing the size of a window defined by inclusive bounds left and right, always use the formula (right - left + 1). Using simple subtraction will undercount your window size by exactly 1 element.
Comments
Post a Comment