The sliding window technique is one of the most powerful and frequently used patterns in array and string problems. It allows us to efficiently solve problems that require examining contiguous subarrays or substrings without recalculating everything from scratch. If you've ever found yourself writing nested loops to check every possible subarray, sliding window is likely the optimization you need.
Understanding the Sliding Window Technique
At its core, the sliding window technique maintains a "window" of elements that slides through the array or string. Instead of checking all possible subarrays independently, we intelligently expand and contract the window based on certain conditions, reusing computations from previous windows.
Why Use Sliding Window?
Consider a problem where you need to find the maximum sum of any
subarray of size k. A naive approach would iterate through
all possible subarrays:
1 | def naive_max_sum(arr, k): |
This has time complexityk
elements. With sliding window, we can achieve
1 | def sliding_window_max_sum(arr, k): |
The key insight: when we slide the window one position to the right, we don't need to recalculate the entire sum. We subtract the element leaving the window and add the new element entering it.
Two Types of Sliding Windows
Sliding window problems fall into two main categories:
Fixed-Size Window
The window size remains constant throughout the algorithm. These problems are typically easier because we know exactly when to move the window.
Characteristics:
- Window size is predetermined (e.g., find maximum sum of subarray of
size
k) - Window moves one position at a time
- Usually involves maintaining a running sum or count
Template:
1 | def fixed_window_template(arr, k): |
Variable-Size Window
The window size changes dynamically based on conditions. These problems are more complex and often require two pointers (left and right) to track window boundaries.
Characteristics:
- Window size varies based on problem constraints
- Window expands when condition is not met
- Window contracts when condition is satisfied
- Often involves finding minimum/maximum window size
Template:
1 | def variable_window_template(s): |
LeetCode 3: Longest Substring Without Repeating Characters
Problem: Given a string s, find the
length of the longest substring without repeating characters.
Example: 1
2
3Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
Analysis: This is a variable-size window problem. We need to maintain a window where all characters are unique. When we encounter a duplicate, we contract the window from the left until the duplicate is removed.

Solution:
1 | def lengthOfLongestSubstring(s): |
Java Version:
1 | public int lengthOfLongestSubstring(String s) { |
Complexity Analysis:
- Time:
- Each character is visited at most twice (once by
right, once byleft) - Space:
- Where
mis the size of the character set (e.g., 26 for lowercase letters)
LeetCode 76: Minimum Window Substring
Problem: 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: 1
2
3Input: s = "ADOBECODEBANC", t = "ABC"
Output: "BANC"
Explanation: The minimum window substring "BANC" includes 'A', 'B', and 'C' from string t.
Analysis: This is a variable-size window problem
where we need to find the smallest window containing all characters from
t. We expand the window until all required characters are
present, then contract to find the minimum valid window.
Solution:
1 | def minWindow(s, t): |
Java Version:
1 | public String minWindow(String s, String t) { |
Complexity Analysis:
- Time:
- Each character in
sis visited at most twice - Space:
- For the hash maps
LeetCode 209: Minimum Size Subarray Sum
Problem: Given an array of positive integers
nums and a positive integer target, return the
minimal length of a contiguous subarray whose sum is greater than or
equal to target. If there is no such subarray, return
0.
Example: 1
2
3Input: target = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: The subarray [4,3] has the minimal length under the problem constraint.
Analysis: This is a variable-size window problem. We expand the window until the sum meets or exceeds the target, then contract to find the minimum valid window.
Solution:
1 | def minSubArrayLen(target, nums): |
Java Version:
1 | public int minSubArrayLen(int target, int[] nums) { |
Complexity Analysis:
- Time:
- Each element is visited at most twice
- Space:
- Only using a few variables
LeetCode 567: Permutation in String
Problem: Given two strings s1 and
s2, return true if s2 contains a
permutation of s1, or false otherwise.
Example: 1
2
3Input: s1 = "ab", s2 = "eidbaooo"
Output: true
Explanation: s2 contains one permutation of s1 ("ba").
Analysis: This is a fixed-size window problem. We
need to check if any window of size len(s1) in
s2 contains the same character frequencies as
s1.
Solution:
1 | def checkInclusion(s1, s2): |
Optimized Version (using array instead of dict):
1 | def checkInclusion(s1, s2): |
Complexity Analysis:
- Time:
- We slide through
s2once - Space:
- Using fixed-size arrays (26 for lowercase letters)
LeetCode 438: Find All Anagrams in a String
Problem: Given two strings s and
p, return an array of all the start indices of
p's anagrams in s.
Example: 1
2
3
4
5Input: s = "cbaebabacd", p = "abc"
Output: [0,6]
Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
Analysis: This is similar to the permutation problem but we need to find all occurrences. We use a fixed-size window and check each position.
Solution:
1 | def findAnagrams(s, p): |
Java Version:
1 | public List<Integer> findAnagrams(String s, String p) { |
Complexity Analysis:
- Time:
- Linear time complexity
- Space:
- Fixed-size arrays
Advanced Problem: Longest Substring with At Most K Distinct Characters
Problem: Given a string s and an
integer k, return the length of the longest substring of
s that contains at most k distinct
characters.
Example: 1
2
3Input: s = "eceba", k = 2
Output: 3
Explanation: The substring is "ece" with length 3.
Solution:
1 | def lengthOfLongestSubstringKDistinct(s, k): |
Complexity Analysis:
- Time:
- Each character visited at most twice
- Space:
- Hash map stores at most
k+1distinct characters
Complexity Analysis Patterns
Understanding time and space complexity for sliding window problems:
Time Complexity
Fixed-size window:
- Typically
where nis the array/string length - Each element enters and leaves the window exactly once
Variable-size window:
- Typically
- Each element visited at most twice (once by right pointer, once by left pointer)
- This is because the left pointer never moves backward
Whywhile loop doesn't reset
left to 0. The left pointer only moves
forward, so the total number of iterations is bounded by
Space Complexity
Using hash maps/dictionaries:
-k is the
number of distinct characters/elements in the window - For lowercase
letters:m is character set size
Using arrays:
-
Common Pitfalls and Debugging Tips
Pitfall 1: Off-by-One Errors
Problem: Incorrect window boundaries when calculating length.
Wrong: 1
max_length = max(max_length, right - left) # Missing +1
Correct: 1
max_length = max(max_length, right - left + 1)
Tip: Remember that right - left + 1
gives the length of substring from left to
right (inclusive).
Pitfall 2: Not Handling Empty Inputs
Problem: Forgetting to check for empty strings or arrays.
Solution: Always add edge case checks:
1
2if not s or len(s) == 0:
return 0 # or appropriate default
Pitfall 3: Incorrect Window Contraction Condition
Problem: Contracting window at wrong time or not contracting enough.
Example - Wrong: 1
2
3while condition:
# Only moves left once, might not be enough
left += 1
Example - Correct: 1
2
3
4while condition:
# Properly remove element and update state
remove_from_window(s[left])
left += 1
Pitfall 4: Using List Instead of Deque for Fixed Window
Problem: Using list.pop(0) which
is
Wrong: 1
2window = []
window.pop(0) # O(n) operation
Correct: 1
2
3from collections import deque
window = deque()
window.popleft() # O(1) operation
Pitfall 5: Not Updating Result at Correct Time
Problem: Updating result before window is valid or after it becomes invalid.
Tip: Think carefully about when the window satisfies the condition:
- For "at least" conditions: Update result when condition is first met, then contract
- For "at most" conditions: Update result continuously as window expands
Debugging Tips
Print window state: Add print statements to track
left,right, and window contents1
print(f"left={left}, right={right}, window={s[left:right+1]}")
Track character counts: For problems involving character frequencies, print the count map
1
print(f"char_count: {char_count}")
Use small test cases: Start with simple examples to verify logic
1
2assert lengthOfLongestSubstring("abc") == 3
assert lengthOfLongestSubstring("aaa") == 1Check boundary conditions: Test with empty strings, single characters, and edge cases
Verify window invariants: Ensure your window always maintains the required properties
When to Use Sliding Window
Sliding window is appropriate when:
- Contiguous subarrays/substrings: Problem asks about contiguous sequences
- Optimization problems: Finding min/max length, sum, or count
- Frequency/count problems: Involving character or element frequencies
- Avoiding recomputation: When naive approach recalculates overlapping regions
Signs that sliding window might help:
- Problem mentions "subarray" or "substring"
- Need to find "minimum" or "maximum" window
- Involves "at most k" or "at least k" constraints
- Naive solution has nested loops checking all subarrays
Template Summary
Fixed-Size Window Template
1 | def fixed_window(arr, k): |
Variable-Size Window Template
1 | def variable_window(s): |
Q&A Section
Q1: How do I know if a problem is a sliding window problem?
A: Look for these indicators:
- Problem asks about contiguous subarrays or substrings
- Need to find minimum/maximum length or sum
- Involves constraints like "at most k distinct characters" or "sum >= target"
- Naive solution would check all possible subarrays (suggesting optimization needed)
Q2: What's the difference between fixed and variable window?
A:
- Fixed window: Size is predetermined (e.g., "find max sum of subarray of size k")
- Variable window: Size changes based on conditions (e.g., "find minimum window containing all characters")
Fixed windows are simpler - you know exactly when to move. Variable windows require tracking when conditions are met.
Q3: Why is sliding window O(n) and not O(n ²)?
A: Even with nested loops, the left pointer never
moves backward. Each element is visited at most twice (once by right
pointer expanding, once by left pointer contracting). Total
iterations:
Q4: Should I use a hash map or array for character counting?
A:
- Array: When character set is small and known (e.g., lowercase letters: 26, digits: 10)
- Hash map: When character set is large or unknown (e.g., Unicode characters)
Arrays are more efficient for small, fixed character sets.
Q5: How do I handle duplicate characters in the window?
A: Use a count map (dictionary or array) instead of
a set. Track frequency of each character: 1
2char_count = {}
char_count[char] = char_count.get(char, 0) + 1
When removing, decrement count and delete key when count reaches 0.
Q6: What if the window condition is complex (multiple constraints)?
A: Break it down: 1. Identify all constraints 2. Track state for each constraint 3. Expand window until all constraints might be satisfied 4. Contract until at least one constraint is violated 5. Update result when all constraints are satisfied
Q7: Can sliding window work with negative numbers?
A: Yes, but be careful:
- For "sum >= target" problems, contracting might not always reduce sum
- May need to track minimum sum ending at each position instead
- Consider using prefix sums or Kadane's algorithm for some cases
Q8: How do I find all valid windows, not just one?
A: Instead of returning early, collect all valid
windows: 1
2
3
4
5result = []
while condition:
if window_valid:
result.append(s[left:right+1]) # or append indices
# Continue sliding
Q9: What's the best way to compare two frequency maps?
A: For small character sets, use arrays and compare
directly: 1
if s1_count == window_count: # Works for lists
For hash maps, compare key-value pairs: 1
if all(window.get(k, 0) == v for k, v in need.items()):
Or use a matches counter to track how many characters
match.
Q10: How do I optimize space complexity?
A:
- Use arrays instead of hash maps when possible (fixed character set)
- Use a single variable to track "matches" instead of comparing entire maps
- Reuse variables instead of creating new data structures
- For some problems, you only need to track differences, not absolute counts
Related LeetCode Problems
Here are more problems to practice sliding window:
Easy:
- Maximum Average Subarray I
- Contains Duplicate II
- Best Time to Buy and Sell Stock
Medium:
- Longest Repeating Character Replacement
- Subarray Product Less Than K
- Maximum Points You Can Obtain from Cards
- Fruit Into Baskets
- Grumpy Bookstore Owner
- Max Consecutive Ones III
Hard:
- Sliding Window Maximum
- Minimum Window Subsequence
- Substring with Concatenation of All Words
Practice Recommendations
- Start with fixed-size windows: Master the simpler pattern first
- Practice variable windows: Work through problems requiring dynamic sizing
- Focus on one language: Get comfortable with templates in Python or Java
- Draw it out: Visualize the window sliding on paper for complex problems
- Time yourself: Practice solving problems within 20-30 minutes
- Review edge cases: Always test with empty inputs, single elements, and boundary conditions
Summary
The sliding window technique is a powerful optimization for problems involving contiguous subarrays or substrings. Key takeaways:
- Two types: Fixed-size (predetermined) and variable-size (dynamic based on conditions)
- Time complexity: Typically
because each element is visited at most twice - Space complexity:
where kis the number of distinct elements, oftenfor fixed character sets - Common patterns: Use hash maps or arrays to track window state, expand until condition met, contract to optimize
- Templates: Memorize the basic templates and adapt them to specific problems
Mastering sliding window will help you solve many array and string problems efficiently. Key: recognizing when to use it and correctly implementing the expand/contract logic. Practice with the problems listed above, and soon you'll be able to identify and solve sliding window problems quickly.
Remember: if you find yourself checking all possible subarrays with
nested loops, sliding window is likely the optimization you need. The
technique transforms
- Post title:LeetCode (4): Sliding Window Technique
- Post author:Chen Kai
- Create time:2023-05-29 00:00:00
- Post link:https://www.chenk.top/en/leetcode-sliding-window/
- Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.