v9.1.1
Menu

Chapter 3: Two Pointers & Sliding Window

Week 3

Master the two pointer technique for scanning sequences from both ends or in tandem, then learn sliding window patterns that maintain a moving subarray to solve range-based problems in linear time. These patterns eliminate nested loops and are among the most frequently tested in interviews.

Topics
8
Demos
5
Videos
3
Min read
34

Chapter Overview

Two pointers and sliding window are arguably the highest-value patterns in all of DSA interviewing. They transform problems that seem to require O(n^2) brute force into elegant O(n) solutions by maintaining state as pointers sweep through the data.

Two pointers come in two flavors. Same-direction pointers (often called "slow and fast") walk through the array together, with the fast pointer exploring ahead while the slow pointer marks a boundary. Opposite-direction pointers start at both ends and move inward, exploiting sorted order or symmetry to skip unnecessary comparisons.

Sliding window extends the two-pointer idea to subarrays and substrings. A fixed-size window slides across the array, updating its aggregate in O(1) per step. A variable-size window expands to include new elements and shrinks from the left when a constraint is violated, solving "longest/shortest subarray with property X" problems efficiently.

Finally, we cover two closely related techniques: prefix sums, which precompute cumulative totals so any range sum can be answered in O(1), and Floyd's cycle detection, which uses fast and slow pointers on linked structures to detect loops in O(1) space.

This chapter covers:

  • Same & opposite direction pointers: Core two-pointer strategies
  • Classic two-pointer problems: Remove duplicates, two sum sorted, valid palindrome
  • Fixed-size sliding window: Maximum sum subarray of size k
  • Variable-size sliding window: Longest and shortest windows with constraints
  • Prefix sums: O(1) range queries after O(n) preprocessing
  • Cycle detection: Floyd's tortoise and hare algorithm

Chapter Roadmap

Click any topic to jump in

Explainer videoInteractive demo
1
Two Pointers

Two indices walking an array together — the building block for in-place transforms, pair search, and sliding windows.

Same-Direction (Fast & Slow) PointersOpposite-Direction Pointers
Two flavours of two pointers

Same-direction pointers for in-place rewriting, opposite-direction for pair search.

2
In-Place Rewriting

Same-direction pointers (read/write) compact arrays in $O(n)$ time and $O(1)$ extra memory.

In-Place Deduplication with Two PointersAllow At Most K Duplicates
3
Two Sum / Three Sum

Opposite-direction pointers find target pairs on sorted arrays in linear time — the basis of $k$-sum reductions.

Two Sum with Opposite PointersThree Sum Reduction
From transforms to symmetric checks
4
Palindrome Checks

Opposite-direction pointers compare mirrored positions — extensions handle filtering and tolerated mismatches.

Basic Palindrome Check with Two PointersValid Palindrome with At Most One Removal
From single pointer to window

Sliding windows generalise two pointers to maintain state over a contiguous range.

5
Fixed Window

A window of exactly $k$ elements — amortised $O(1)$ per step using incremental updates.

Maximum Sum Subarray of Size KSliding Window with Auxiliary Data Structures
6
Variable Window

Expand-then-shrink windows — each index is visited at most twice, keeping the total $O(n)$.

Longest Window Pattern (Expand Until Invalid)Shortest Window Pattern (Shrink After Valid)
Range queries and cycle finding

Prefix sums answer range queries; tortoise & hare uses two pointers on linked structures.

7
Prefix Sums

Cumulative sums turn range-sum queries into two array reads — combine with hash maps for subarray-sum problems.

Building and Using Prefix SumsSubarray Sum Equals K with Prefix Sum + Hash Map
8
Floyd's Tortoise & Hare

Two pointers moving at different speeds detect cycles in $O(n)$ time and $O(1)$ space.

Tortoise and Hare AlgorithmFinding Duplicates with Floyd's Algorithm

Topics

8 topics in this chapter

Suppose you must check whether any two numbers in a list of 100,000 values add up to a target, or strip every zero out of an array without allocating a second one. The obvious approach compares every pair with nested loops, about five billion comparisons for 100,000 elements. That is far too slow, and most of those comparisons are wasted because their outcome was predictable from ones already made.

The previous chapter, Binary Search, showed how ordered data lets one comparison discard half of the candidates. Two pointers apply a similar idea to a linear sweep: two indices move through the data, and each comparison lets one of them advance past an element that can never matter again. Since each pointer moves at most n times, the total work is O(n).

This topic introduces the two basic layouts. Same-direction pointers, a fast reader and a slow writer, compact or partition an array in place. Opposite-direction pointers start at both ends and close in, using sorted order or symmetry to decide which end to move. Every later topic in this chapter builds on one of these two shapes.

Definition

The two-pointer technique scans a sequence with two indices whose positions encode an invariant. Same-direction pointers both move left to right, a fast read index ahead of a slow write index. Opposite-direction pointers start at the two ends and move inward. Because neither pointer ever moves backwards, the scan finishes in O(n) time with O(1) extra space.

In this topic

  1. 1Same-Direction (Fast & Slow) Pointers
  2. 2Opposite-Direction Pointers
1 of 2
Same-Direction (Fast & Slow) Pointers

In-place problems forbid a second array, yet you still need to separate the elements you keep from the ones you drop. Same-direction pointers do this with two indices that both start at 0. The fast index reads every element exactly once; the slow index marks where the next kept element should be written. The invariant is that nums[0..slow-1] holds exactly the kept elements, in their original order. When nums[fast] passes the test, write or swap it into position slow and increment slow; otherwise only fast advances. A common bug is incrementing slow unconditionally, which keeps everything. This one pattern powers removal, deduplication, and stable partitioning.

Mathematical Intuition

Two indices ii (fast, read) and jj (slow, write) both advance from 00. The invariant is that a[0..j−1]a[0..j-1] already holds the finalised output. Because each pointer moves only forward and at most nn times, the total work is Θ(n)\Theta(n) time and O(1)O(1) extra space — strictly better than any solution that allocates a new array.

Example:

Given an array [0, 1, 0, 3, 12], move all zeros to the end while maintaining the relative order of non-zero elements. Do this in-place.

2 of 2
Opposite-Direction Pointers

One pointer starts at the beginning, the other at the end. They move toward each other based on a comparison or condition. This is ideal for sorted arrays (where the sum of endpoints guides which pointer to move), palindrome checking (comparing characters from both ends), and container problems (where width decreases as pointers converge). The loop runs while left < right, visiting each element at most once for O(n) time.

Mathematical Intuition

Two indices ll (from the left) and rr (from the right) close in on each other. At each step one of them moves inward, so the combined distance r−lr - l decreases by at least 11 per iteration. Starting from n−1n - 1, the loop runs at most n−1n - 1 times — Θ(n)\Theta(n). The invariant depends on the problem (e.g., 'the answer, if any, involves some l′≥ll' \ge l and r′≤rr' \le r').

Example:

Given a sorted array [-4, -1, 0, 3, 10], return a new array of each element squared, sorted in non-decreasing order.