TL;DR
- If the problem asks for a contiguous subarray or substring, I check sliding window early.
- If the input is sorted or I can reason from both ends, I check two pointers.
- The key skill is deciding what makes the window valid and when to shrink it.
- These patterns turn many
O(n²)solutions intoO(n).
Context
This is one of the biggest pattern jumps in interview prep. Once I see boundaries instead of nested loops, a whole class of problems becomes much easier to solve and explain.
The Approach
For a fixed-size window, I track the current summary and roll it forward.
For a variable-size window, I use:
- expand right
- check validity
- shrink left until valid
- record best answer
function maxSumSubarray(nums: number[], size: number): number {
let windowSum = 0
for (let index = 0; index < size; index += 1) {
windowSum += nums[index]
}
let best = windowSum
for (let right = size; right < nums.length; right += 1) {
windowSum += nums[right] - nums[right - size]
best = Math.max(best, windowSum)
}
return best
}
function hasPairWithSum(nums: number[], target: number): boolean {
let left = 0
let right = nums.length - 1
while (left < right) {
const sum = nums[left] + nums[right]
if (sum === target) return true
if (sum < target) left += 1
else right -= 1
}
return false
}
Trade-offs
- Sliding window is excellent for contiguous ranges, but it does not help if the problem is not range-based.
- Two pointers are clean on sorted input, but sometimes sorting changes the original-index requirement.
- These patterns are fast once recognized, but easy to misuse if I have not defined the invariant clearly.