Two Pointers 101
Fundamental · 4 chapters · 8 min read · Walk an array from both ends and replace an O(n²) search with a single pass.
Practise this in the app All guides
What two pointers is and when to use it
The idea
Two pointers means keeping two indices into the same sequence (or one index into each of two sequences) and moving them according to a rule, so that together they cover all useful pairs in O(n) instead of O(n²). The trick works because of some order in the data: once a pointer moves past a position, you can prove you never need to return to it.
There are three shapes you will see again and again:
- Opposite ends.
leftstarts at 0,rightat the end, and they move towards each other. Used on sorted arrays and palindromes. - Same direction, different speeds. A
readpointer scans every element and awritepointer marks where the next kept element goes. Used for in-place filtering and removing duplicates. - One pointer per sequence. Walk two strings or arrays together, like the merge step of merge sort, or checking whether one string is a subsequence of another.
Signals in a problem statement
- The array is sorted, or sorting it does not break the question.
- "Find a pair or triplet with sum equal to target."
- "Palindrome", "reverse", "compare from both ends".
- "Remove in place", "move zeros", "return the new length".
- "Is
sa subsequence oft?" - "Maximise area or width between two lines."
Why it is correct
For a sorted array with left and right, if a[left] + a[right] is too small, then pairing a[left] with anything left of right is also too small, so a[left] can be discarded. That one-line argument is what interviewers want to hear. Always be ready to say why moving a pointer cannot skip the answer.
Core patterns with templates
1. Pair sum on a sorted array
def pair_sum(a, target):
lo, hi = 0, len(a) - 1
while lo < hi:
s = a[lo] + a[hi]
if s == target:
return [lo, hi]
if s < target:
lo += 1
else:
hi -= 1
return []
2. Palindrome check that skips non-letters
def is_palindrome(s):
lo, hi = 0, len(s) - 1
while lo < hi:
if not s[lo].isalnum():
lo += 1
elif not s[hi].isalnum():
hi -= 1
elif s[lo].lower() != s[hi].lower():
return False
else:
lo += 1
hi -= 1
return True
3. Read and write pointers
def remove_duplicates_sorted(a):
w = 0
for r in range(len(a)):
if r == 0 or a[r] != a[r - 1]:
a[w] = a[r]
w += 1
return w
4. Subsequence check
def is_subsequence(s, t):
i = 0
for ch in t:
if i < len(s) and s[i] == ch:
i += 1
return i == len(s)
5. Three numbers summing to zero
Sort, fix the first element, then run pattern 1 on the rest. Skip equal neighbours to avoid duplicate triplets.
def three_sum(a):
a.sort()
out = []
for i in range(len(a) - 2):
if i and a[i] == a[i - 1]:
continue
lo, hi = i + 1, len(a) - 1
while lo < hi:
s = a[i] + a[lo] + a[hi]
if s < 0:
lo += 1
elif s > 0:
hi -= 1
else:
out.append([a[i], a[lo], a[hi]])
lo += 1
while lo < hi and a[lo] == a[lo - 1]:
lo += 1
hi -= 1
return out
Example: [-1,0,1,2,-1,-4] sorts to [-4,-1,-1,0,1,2] and yields [-1,-1,2] and [-1,0,1].
Complexity, mistakes and edge cases
Complexity
| Pattern | Time | Extra space |
|---|---|---|
| Opposite ends on sorted data | O(n) | O(1) |
| Read/write filter | O(n) | O(1) |
| Sort then two pointers | O(n log n) | O(1) to O(n) for the sort |
| Fixed element plus pair (3-sum) | O(n²) | O(1) besides output |
Common mistakes
- Using
<=instead of<in the loop condition, which lets one element pair with itself. - Forgetting to move a pointer in some branch, which causes an infinite loop. Every iteration must move at least one pointer.
- Duplicate results in 3-sum style questions. Skip equal values both for the fixed element and after a match.
- Sorting when indices matter. If the answer must be original indices, sorting loses them; sort
(value, index)pairs or use a hash map instead. - Character classes. Python's
isalnum()accepts digits and Unicode letters; confirm with the interviewer what counts.
Edge cases
Empty array, one element, all elements equal, no valid pair, many valid pairs, negative numbers, and integer overflow in languages other than Python (mention it if you are coding in Java or C++).
The greedy argument for "container with most water"
With two lines at lo and hi, the area is min(h[lo], h[hi]) * (hi - lo). Moving the taller line inward can only shrink the width and cannot raise the minimum, so it never helps. Therefore always move the shorter line. Being able to state this argument is often worth as much as the code itself, because it shows you understand why the pointer moves are safe.
Variations and practise
How interviewers twist it
- Closest sum instead of exact. Track the best difference seen while running the same pointer moves.
- Count pairs instead of finding one. When
a[lo] + a[hi] < target, every index betweenloandhialso pairs withlo, so addhi - loat once. - k-sum. Generalise 3-sum by recursion: fix one element, solve (k-1)-sum on the rest, until you reach the two-pointer base case. Time is O(n^(k-1)).
- Unsorted input with "O(1) space". Sorting in place is often acceptable; ask.
- Linked lists. Fast and slow pointers find the middle of a list, detect a cycle, or locate the n-th node from the end. You will meet these in the Linked List card.
- Strings with a backspace character. Walk both strings from the end, skipping characters that are erased, and compare as you go.
Two pointers versus sliding window
Both use two indices. In sliding window the two pointers define a contiguous range whose contents you track (a sum, a count). In classic two pointers you usually care about the two elements at the pointers. Knowing which one you are using helps you explain your approach.
Practise
The problems below start with palindromes and subsequence checks, move to pair sums on sorted input, and finish with the greedy area argument and triplets. For each one, say out loud why moving a pointer cannot skip the answer before you code it.
Practise
Easy
- 605. Valid Palindrome
- 606. Is Subsequence
- 612. Reverse the Shelf Labels
- 616. Mirror Ticket Number
- 617. Park the Empty Crates
- 618. Strip the Banned Code
- 619. Distinct Sorted Readings
- 620. Fewest Swaps to Front-Load Evens
- 621. Shared Badges of Two Teams
- 622. Union of Sorted Catalogs
- 623. Cheapest Dial Turns to a Mirror
- 624. Count Affordable Pairs
- 625. Flip a Section of the Playlist
- 626. Word-Level Mirror Sentence
- 627. Find the Lost Parcel
- 629. Best Pair Under the Limit
- 630. Distinct Magnitudes in a Sorted List
- 631. Present in All Three Ledgers
- 632. Closest Pair Sum to a Target
- 633. Tug-of-War Tally
- 634. K-th of Two Sorted Queues
- 635. Longest Mirrored Prefix
- 636. One Smudge Allowed
- 637. Balanced Seesaw Row
- 638. Best Combo Under Budget
- 639. Nearest Gap Between Two Words
- 640. Interleave the Deck Halves
- 641. Mirror Bracket String
- 642. Match Buddies Within Tolerance
- 643. Upside-Down Number
- 644. Double the Zeros
- 645. Reverse in Alternate Blocks
- 646. Digit-Square Loop
- 647. Tightest k Scores
- 648. Count Distinct Midpoints
- 649. Two Swapped Entries
- 650. Count Cross Overtakes
- 651. Summarize Ticket Runs
- 652. Erase by Mirror Pieces
- 653. Cheapest Paired Workload
- 694. Symmetric Swaps to Sort
- 699. Extract the Pattern Repeatedly
- 759. Not Yet Returned Books
- 760. Two-Voice Transcript
- 798. Distance to the Nearest Lamp
- 799. Planks Over Broken Boards
- 800. Low-High Alternation
- 801. Longest Quiet Gap in Two Schedules
- 802. Overlap of Two Messages
Medium
- 607. Two Sum II - Input Array Is Sorted
- 608. Container With Most Water
- 609. 3Sum
- 613. Nearest Triple Sum
- 614. Four-Way Split to a Target
- 615. Count Triples Under a Cap
- 654. Count Buildable Triangles
- 655. Fewest Rafts Across
- 656. Lightest Heaviest Pair
- 657. Distinct Gap Pairs
- 658. Keep at Most Two Copies
- 659. Overlap of Two Shift Lists
- 660. Subtract Blocked Intervals
- 661. Longest Ridge in the Terrain
- 662. Longest Word by Erasing
- 663. Count Hidden Words
- 664. Stretched Shouts
- 665. Trim Matching Ends
- 666. Slide the Robots
- 667. Repeated Ticket in a Range
- 668. One-Way Loop in a Ring
- 669. Pair Across Two Search Trees
- 670. Fewest Merges to a Mirror
- 671. Mirror From Two Strings
- 672. Alternate Signs in Order
- 673. Spend or Cash Cards
- 674. Shortest Cut to Sorted
- 675. Most Target Pairs Removed
- 676. Balanced Skill Duos
- 677. Pair Climbers With Ropes
- 678. Widest Valid Span of Two Lists
- 679. Earliest Common Meeting Slot
- 680. Sorted Parabola Values
- 681. Roomiest Seat on the Bench
- 682. Square Equals Product Triples
- 683. Longest Upward Reach
- 684. Best-Paying Gigs
- 685. Home Advantage Pairs
- 686. Spread After Three Changes
- 687. Painting From Both Ends
- 688. Closest Across Three Lists
- 689. Triples in a Sum Range
- 690. Total Gap Between Two Lists
- 691. Narrowest Band After Shifts
- 692. Most Removable Letters
- 693. Longest Climb With One Skip
- 695. Last Seat on the Shuttle
- 696. Count Overlapping Booking Pairs
- 697. Most Equal After Raises
- 698. Most Points on an Arc
- 700. Longest Run That Hides in Another
- 701. Swap to Merge Two Shelves
- 702. Distinct Three-Letter Mirrors
- 703. Sentences One Insertion Apart
- 704. Heater Radius for Cottages
- 705. N-th Number Built From 3, 5 and 7
- 706. Compare Firmware Versions
- 707. Ring Seating With the Smallest Jump
- 708. Docks Needed at the Harbour
- 709. Equal Prefix and Suffix Loads
- 710. Pair Reaching a Threshold
- 711. Multiply Run-Length Lists
- 712. Pairs in a Turned Sorted List
- 713. Same After One Reversal
- 714. Chargers Within Reach
- 715. Count Sums of Two Others
- 716. Right-Angle Stick Triples
- 717. Fewest Changes to a Periodic Mirror
- 718. Insert Missing Beats
- 719. Equalize Two Dice Totals
- 720. Move to Front to Match
- 721. Evenly Spaced Value Triples
- 722. Pair the Chopsticks
- 750. Longest Near Mirror
- 751. Everyone's Free Time
- 752. Blooms at Visit Time
- 757. Pair Sums Modulo Under a Cap
- 761. Pair Sums in Range Across Lists
- 762. Widest Gap Across Shelves
- 763. Ordered Picks From Three Shelves
- 764. Neighbours Within Reach
- 765. Turn Into a Mirror
- 766. Order by Distance From Home
- 767. Best Single Reversal
- 768. Two-Mirror Split
- 769. Subsequence With One Typo
- 770. Same Coverage Check
- 771. Tight Flock
- 772. Shop From Both Aisle Ends
- 773. Pop Order From Both Ends
- 774. Shortest Merged Roster
- 775. Line Up the Smallest Name
- 776. Badge Initials Match
- 777. Fewest Copies to Hide a Word
- 778. Trade One Snack
- 779. Contained Sessions
- 780. Two-Ends Snack Race
- 781. Slide the Beads
- 782. Cut Out to All Distinct
- 783. Mirrored Sum Chunks
- 784. Lattice Points Inside a Disc
- 785. Longest Chain by One Letter
- 791. Pair Red and Blue Posts
- 792. Tight k-Squads
- 794. Cheapest Repaint to a Mirror
- 796. Split Message Pairs
- 797. Up-Down Signal Sequence
- 803. Independent Letter Blocks
- 804. Equal-Total Pairing Across Teams
Hard
- 610. Trapping Rain Water
- 611. Find K-th Smallest Pair Distance
- 628. Richest Walk Across Two Trails
- 723. Three Matching Bit Segments
- 724. K-th Smallest Cross Product
- 725. Strongest Segment Around k
- 726. K-th Smallest Pair Total at Scale
- 727. Count Mirror Substrings at Scale
- 728. Two Odd Mirrors Max Product
- 729. Mirror With k Deletions
- 730. Total Spread of All Subsets
- 731. Longest Prefix-Suffix Mirror
- 732. Market Haul Within a Step Budget
- 733. Lifts With Limited Tonics
- 734. Best Pair With a Distance Cap
- 735. Budget Quadruples
- 736. Bounded Extremes Stretches
- 737. Flower Bed Showcase
- 738. Count Removable Blocks
- 739. Reunion Square on the Grid
- 740. Gather the Tokens Tightly
- 741. Telescope Field of View
- 742. Closest Pair of Towers
- 743. Weighted Stretches Under a Cap
- 744. Cheapest Sheet Slicing
- 745. Make Shelves Alike
- 746. Climb Picking From Both Ends
- 747. Busy Node Pairs
- 748. Least Packing Waste
- 749. k Mirror Parts With Fewest Edits
- 753. Windows With Few Inversions
- 754. Adjacent Swaps to an Anagram
- 755. Most Equal With Moves Both Ways
- 756. Night Bridge Crossing
- 758. Distinct Mirror Subsequences
- 786. Richest Mirror Subsequence
- 787. Three Mirror Pieces
- 788. Smoothest Zipper Merge
- 789. Longest Near Match Under Shift
- 790. Sort by Sending to Ends
- 793. m Tarps on a Line
- 795. Fastest Sweep of the Tracks