Two Pointers & Sliding Windows: Elegance in O(n)


Imagine going through a list once and solving a problem that would otherwise need nested loops and a prayer.
That’s the magic of Two Pointers and Sliding Windows — algorithms that give you O(n) time for problems that feel like they should be O(n²).
If you're still looping through every substring like it's 2015, this one's for you.
🧠 What Are Two Pointers?
Two Pointers = Literally using two variables (often left
and right
) to traverse data efficiently.
They work when:
Your data is linear (arrays, strings)
The problem involves comparison, matching, or scanning ranges
You want to avoid unnecessary rework or overlap
🪟 Sliding Window = Two Pointers + Constraint
A sliding window is a specific case where:
You're looking at a "window" of elements (contiguous)
You grow/shrink the window as you move across the array
You keep track of something: sum, frequency, length, etc.
Think of it like a moving camera on an array.
Instead of recording every moment, you just adjust the lens.
🤯 Why Use These?
Feature | Benefit |
One pass | O(n) runtime |
In-place traversal | O(1) extra space (often) |
Real-world friendly | Streaming, memory, search stuff |
Interviewer friendly | “Oh wow, you optimized that? 😳” |
🔥 Problem 1: Longest Substring Without Repeating Characters
Given a string, return the length of the longest substring without repeating characters.
❌ Brute-force
Check every substring.
Time: O(n²).
Tears: infinite.
✅ Sliding Window
function lengthOfLongestSubstring(s) {
let map = new Map();
let left = 0, maxLen = 0;
for (let right = 0; right < s.length; right++) {
if (map.has(s[right])) {
left = Math.max(map.get(s[right]) + 1, left);
}
map.set(s[right], right);
maxLen = Math.max(maxLen, right - left + 1);
}
return maxLen;
}
The
left
pointer jumps past duplicatesThe
right
pointer keeps expandingResult: smooth substring gliding in O(n)
🍟 Problem 2: Minimum Size Subarray Sum
Given an array of positive integers and a target, return the minimum length of a subarray whose sum is ≥ target.
function minSubArrayLen(target, nums) {
let sum = 0, left = 0, minLen = Infinity;
for (let right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
minLen = Math.min(minLen, right - left + 1);
sum -= nums[left++];
}
}
return minLen === Infinity ? 0 : minLen;
}
You just:
Kept a window of elements
Moved
right
to expandMoved
left
to shrinkMaintained constraint:
sum >= target
That’s the sliding window in action.
👀 Problem 3: Check If Array Has Two Elements That Sum to Target (Sorted)
Given a sorted array, does any pair sum to a target?
function hasPairWithSum(nums, target) {
let left = 0, right = nums.length - 1;
while (left < right) {
const sum = nums[left] + nums[right];
if (sum === target) return true;
if (sum < target) left++;
else right--;
}
return false;
}
Two pointers:
One from start
One from end
Narrowing based on sum comparison
Elegant. Sorted. Efficient.
🧮 Problem 4: Container With Most Water
Given heights, find max water two lines can trap.
function maxArea(height) {
let left = 0, right = height.length - 1;
let maxArea = 0;
while (left < right) {
const h = Math.min(height[left], height[right]);
const w = right - left;
maxArea = Math.max(maxArea, h * w);
if (height[left] < height[right]) left++;
else right--;
}
return maxArea;
}
We reduce the smaller height
Try to expand the area
Achieves max with one pass
🧠 Recap: When to Use What?
Problem Type | Technique |
Substrings/Subarrays with constraint | Sliding Window |
Sorted Array + Pairwise Logic | Two Pointers |
Max/Min in contiguous block | Sliding Window |
Range Scan with Jumping Indexes | Two Pointers |
🪄 Real-World Analogies
Two Pointers: You're at both ends of a hallway, walking toward the truth
Sliding Window: You're trying to hold the perfect amount of popcorn in a leaky bag
Brute Force: You’re checking every house on the block for your lost AirPods.
Two Pointers: You AirDrop ping both ends of the street and narrow it down.
🚫 Common Mistakes
❌ Resetting left
incorrectly
❌ Forgetting to shrink the window
❌ Not updating max/min values inside loops
❌ Assuming all problems fit sliding windows
✨ Tip: Always draw out the index movements if confused.
🧵 Final Thoughts
Two pointers and sliding window aren’t just space-savers.
They’re mental models — ways to traverse time, memory and constraints intelligently.
Brute force loops? Outdated.
Smart traversal? That’s you now.
So next time someone says,
"Try every possible pair..."
You say: "Nah. I’ll just slide into O(n) real quick."
📚 Want more creative DSA goodness?
Follow Code Like You Mean It — DSA Edition for more.
Until then — keep your windows sliding, your pointers tight, and your runtime clean,
Peace ✌️
Subscribe to my newsletter
Read articles from Faiaz Khan directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Faiaz Khan
Faiaz Khan
Hey! I'm Faiaz — a frontend developer who loves writing clean, efficient, and readable code (and sometimes slightly chaotic code, but only when debugging). This blog is my little corner of the internet where I share what I learn about React, JavaScript, modern web tools, and building better user experiences. When I'm not coding, I'm probably refactoring my to-do list or explaining closures to my cat. Thanks for stopping by — hope you find something useful or mildly entertaining here.