Sliding Window Technique
The Sliding Window pattern is used to perform a required operation on a specific window size of a given array or string, such as finding the longest substring containing all 1s. Sliding Windows start from the 1st element and keep shifting right by one element and adjust the length of the window according to the problem that you are solving.
In many cases, this technique converts a nested loop operation (O(N2)) into a single loop operation (O(N)).
1. Types of Sliding Windows
There are two primary types of sliding windows:
- Fixed Size Window: The window size is fixed (e.g., “find the maximum sum of any subarray of size
k”). - Dynamic Size Window: The window grows or shrinks based on constraints (e.g., “find the smallest subarray with a sum greater than
s”).
2. The Mathematical Anchor: Loop Invariants
To prove a sliding window algorithm is correct, we use a Loop Invariant. This is a property that must be true at the beginning of every iteration.
The Invariant Blueprint
“For any window defined by
[left, right], the state (e.g.,current<sub>sum</sub>,frequency<sub>map</sub>) accurately reflects the elements within that boundary, and the constraint is satisfied locally.”
Example: Longest Substring Without Repeating Characters
- Initialization:
left = 0,right = 0. Window is empty or has 1 char. Invariant holds. - Maintenance: If we add
arr[right]and it’s a duplicate, we incrementleftuntil the duplicate is gone. After this adjust, the window[left, right]once again contains only unique characters. - Termination: When
rightreaches the end, we have checked every possible valid window starting position, and themax<sub>length</sub>tracks the global optimum.
3. Interactive Visualizer: Dynamic Sliding Window
The following visualizer demonstrates finding the Longest Substring Without Repeating Characters. Watch how the left and right pointers move. The window expands (right moves) as long as characters are unique. When a duplicate is found, the window shrinks (left moves) until the duplicate is removed.
4. Problem 1: Longest Substring Without Repeating Characters
Difficulty: Medium
Given a string s, find the length of the longest substring without duplicate characters.
Example:
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Solution Walkthrough
We can use the Sliding Window technique with a HashSet (or a boolean array/map) to keep track of characters in the current window.
- Initialize
left = 0,right = 0,maxLen = 0. - Iterate
rightfrom 0 to end. - If
s[right]is in the set, it means we have a duplicate. Incrementleftand removes[left]from the set untils[right]is no longer in the set. - Add
s[right]to the set. - Update
maxLen = max(maxLen, right - left + 1).
View Java Solution
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
class Solution {
public int lengthOfLongestSubstring(String s) {
Set<Character> chars = new HashSet<>();
int left = 0;
int maxLen = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
// If duplicate found, shrink window from left
while (chars.contains(c)) {
chars.remove(s.charAt(left));
left++;
}
chars.add(c);
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
}
View Go Solution
package main
func lengthOfLongestSubstring(s string) int {
chars := make(map[byte]bool)
left := 0
maxLen := 0
for right := 0; right < len(s); right++ {
c := s[right]
// If duplicate found, shrink window from left
for chars[c] {
delete(chars, s[left])
left++
}
chars[c] = true
currentLen := right - left + 1
if currentLen > maxLen {
maxLen = currentLen
}
}
return maxLen
}
5. Problem 2: Minimum Window Substring
Difficulty: Hard
Given two strings s and t, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no such substring, return the empty string "".
Example:
Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Solution Walkthrough
This problem requires a dynamic sliding window with frequency counting.
- Count the frequency of characters in
t. - Expand
rightpointer to include characters froms. - When the window contains all characters from
t(valid window), try to shrink it from theleftto make it minimal. - Keep track of the minimum window size and starting position found so far.
View Java Solution
import java.util.HashMap;
import java.util.Map;
class Solution {
public String minWindow(String s, String t) {
if (s.length() < t.length()) return "";
Map<Character, Integer> need = new HashMap<>();
for (char c : t.toCharArray()) {
need.put(c, need.getOrDefault(c, 0) + 1);
}
int left = 0, right = 0;
int required = need.size(); // Number of unique characters needed
int formed = 0; // Number of unique characters satisfying the count
Map<Character, Integer> window = new HashMap<>();
int[] ans = {-1, 0, 0}; // length, left, right
while (right < s.length()) {
char c = s.charAt(right);
window.put(c, window.getOrDefault(c, 0) + 1);
if (need.containsKey(c) && window.get(c).intValue() == need.get(c).intValue()) {
formed++;
}
// Try to contract the window
while (left <= right && formed == required) {
c = s.charAt(left);
// Save smallest window
if (ans[0] == -1 || right - left + 1 < ans[0]) {
ans[0] = right - left + 1;
ans[1] = left;
ans[2] = right;
}
// Remove from left
window.put(c, window.get(c) - 1);
if (need.containsKey(c) && window.get(c).intValue() < need.get(c).intValue()) {
formed--;
}
left++;
}
right++;
}
return ans[0] == -1 ? "" : s.substring(ans[1], ans[2] + 1);
}
}
View Go Solution
package main
import "math"
func minWindow(s string, t string) string {
if len(s) == 0 || len(t) == 0 {
return ""
}
need := make(map[byte]int)
for i := 0; i < len(t); i++ {
need[t[i]]++
}
required := len(need)
formed := 0
window := make(map[byte]int)
l, r := 0, 0
ans := []int{-1, 0, 0} // length, left, right
for r < len(s) {
c := s[r]
window[c]++
if count, ok := need[c]; ok && window[c] == count {
formed++
}
for l <= r && formed == required {
c = s[l]
if ans[0] == -1 || r-l+1 < ans[0] {
ans[0] = r - l + 1
ans[1] = l
ans[2] = r
}
window[c]--
if count, ok := need[c]; ok && window[c] < count {
formed--
}
l++
}
r++
}
if ans[0] == -1 {
return ""
}
return s[ans[1] : ans[2]+1]
}
6. Deep Dive Strategy Lab: Sliding Window Technique
Intuition Through Analogy
Think of this chapter like organizing items on a warehouse shelf. The goal is not to memorize a fixed trick, but to repeatedly answer:
- What is the bottleneck?
- Which constraint dominates (time, memory, latency, correctness)?
- Which representation makes the bottleneck easier to eliminate?