Skip to content
Hello Python
1/7

Arrays & Strings — Two Pointers / Sliding Window

Topic 1 of 7, with 3 concept checks. Recognizing when to use two pointers or a sliding window

Shrink the search space with moving boundaries

Array boundaries

Define what each pointer or window boundary means, state the invariant it preserves, and justify every movement so array and string scans remain linear and explainable.

Core lesson 01

Reach for two pointers when the array is sorted (or can be sorted) and you need pairs/triples satisfying a condition, or when comparing from both ends (palindromes) - turns an O(n^2) nested loop into O(n).

The two-pointer pattern maintains two indices moving toward each other (or in the same direction at different speeds) based on a comparison, eliminating the need to check every pair explicitly. It applies whenever moving one pointer safely rules out a whole range of possibilities - most commonly on sorted arrays (Two Sum II, 3Sum) or symmetric checks (palindromes).

Python example
def two_sum_sorted(nums, target):
    left, right = 0, len(nums) - 1
    while left < right:
        s = nums[left] + nums[right]
        if s == target:
            return [left, right]
        elif s < target:
            left += 1
        else:
            right -= 1
    return []

What to remember

How do you recognize a two-pointer problem?

Common footguns

  • Trying two pointers on an unsorted array without sorting first (or realizing sorting changes required output, like original indices) - the pattern relies on monotonic movement being meaningful.

Core lesson 02

Sliding window applies to contiguous subarray/substring problems (longest, shortest, count matching a condition) - grow from the right, shrink from the left whenever the constraint is violated, tracking the best result.

A brute-force approach checks every subarray, O(n^2) or worse. A sliding window maintains a valid (or trackable) range [left, right], expanding right by one each step and updating running state (sum, character counts); when that state violates the constraint, it shrinks from the left until valid again. Each pointer moves forward at most n times total, giving O(n).

Python example
def longest_unique_substring(s):
    seen = set()
    left = best = 0
    for right, ch in enumerate(s):
        while ch in seen:
            seen.remove(s[left])
            left += 1
        seen.add(ch)
        best = max(best, right - left + 1)
    return best

What to remember

How do you recognize a sliding window problem, and what's the core template?

Common footguns

  • Shrinking the window with an if instead of a while when multiple violations can stack up - an if only fixes one step of invalidity, a while fully restores validity.

Core lesson 03

Use a hash map when the array is unsorted and you can't (or shouldn't) sort it - e.g. when the answer needs original indices - trading O(n) space for avoiding the O(n log n) sort two pointers would otherwise require.

Two Sum is the canonical example: on a sorted array, two pointers solves it in O(n) after an O(n log n) sort - but if you need the ORIGINAL indices of the two numbers, sorting destroys that information, so a hash map (value -> original index) solves it in a single O(n) pass without ever sorting.

Python example
def two_sum_indices(nums, target):
    seen = {}   # value -> index
    for i, num in enumerate(nums):
        complement = target - num
        if complement in seen:
            return [seen[complement], i]
        seen[num] = i
    return []

What to remember

When should you reach for a hash map instead of two pointers, even on similar-looking problems?

Common footguns

  • Sorting an array to use two pointers, then returning the sorted positions instead of the original indices the problem actually asked for.

Python lab

Browser Python lab

Runtime · idle

Python loads on your first run. Your code stays in this browser.

Best practices

  • Two pointers: sorted data, pair/triple sums, palindromes, removing duplicates in place.
  • Sliding window: contiguous subarray/substring with a size, sum, or character-set constraint.
  • Hash map: unsorted data, need O(1) lookups, or must preserve original order/indices.
  • Always ask: does sorting lose information the answer needs (like original indices)?

Apply the concept in Interview practice

Two SumeasyLeetCode #1 · O(n) time

Hash map of value to index, single pass, checking for the complement before inserting.

Open problem
3SummediumLeetCode #15 · O(n^2) time

Sort the array, fix one number, then two-pointer the rest for pairs summing to its negation, skipping duplicates at every level.

Open problem
Container With Most WatermediumLeetCode #11 · O(n) time

Two pointers from both ends; always move the pointer at the shorter line inward, since moving the taller one can never increase the area.

Open problem
Longest Substring Without Repeating CharactersmediumLeetCode #3 · O(n) time

Sliding window with a set/dict of characters currently in the window; shrink from the left whenever a repeat is found.

Open problem
Minimum Window SubstringhardLeetCode #76 · O(n) time

Sliding window with a character-count dict of the target; expand right until the window contains all required characters, then shrink left while still valid, tracking the smallest valid window.

Open problem
Trapping Rain WaterhardLeetCode #42 · O(n) time, O(1) space

Two pointers from both ends tracking the max height seen so far on each side; water at each position is bounded by the smaller of the two maxes.

Open problem

Concept checks

Q01

How do you recognize a two-pointer problem?

Q02

How do you recognize a sliding window problem, and what's the core template?

Q03

When should you reach for a hash map instead of two pointers, even on similar-looking problems?