DSABeginner6 min readPart 3 of 16

Two Pointers

The two pointers technique uses two indices to walk through a data structure, which often turns an O(n²) pair of nested loops into a single O(n) pass. It is one of the most tested patterns in coding interviews.

Can you explain two pointers out loud?

I'm Alex. Read this, then I'll interview you on real problems and push on the parts you skip.

The idea in one pictureCore idea

Instead of checking every pair with two loops, you keep two positions, look at the elements under them, and use what you see to decide which one to move. Every step moves at least one pointer, so the whole walk takes one pass.

nums (sorted)12471115012345leftrightTwo indices, one pass: each step moves left forward orright back.
DiagramThe starting position for the opposite-ends pattern.

There are three ways the pointers can move. Almost every two-pointer problem is one of them:

Opposite endssorted

Start at both ends and walk toward each other. Pair sums, palindromes, container problems.

Same directionread / write

One pointer reads ahead, the other marks where to write. Removing duplicates, partitioning.

Fast and slowspeeds

One pointer moves one step, the other two. Cycle detection, finding the middle of a list.

Pattern 1: Opposite endsPattern

Two pointers start at opposite ends of a sorted array and move toward each other. Because the array is sorted, the sum tells you which pointer to move: too big means the right value is too large, too small means the left value is too small.

Two Sum II, target = 15

12471115012345LR1 + 15 = 16 is too big, so move R left12471115012345LR1 + 11 = 12 is too small, so move L right12471115012345LRAfter one more step: 4 + 11 = 15, found it
WalkthroughEach comparison throws away one element for good, which is why the pass is O(n).
Two Sum II (sorted array)TypeScript
function twoSumII(nums: number[], target: number): [number, number] {
  let left = 0, right = nums.length - 1;
  while (left < right) {
    const sum = nums[left] + nums[right];
    if (sum === target) return [left + 1, right + 1];
    else if (sum < target) left++;
    else right--;
  }
  return [-1, -1];
}
TimeO(n)SpaceO(1)

Pattern 2: Same directionPattern

Both pointers move the same way. One pointer (read) leads and looks at every element; the other (write) follows and marks where the next element you want to keep should go. It is used for removing duplicates and partitioning in place.

Remove duplicates from [1, 1, 2, 2, 3]

kept: 3 unique values1232301234writereadEverything left of write is the answer. What is rightof it no longer matters.
DiagramThe array after the pass: write = 3 is the new length.
Remove duplicates from a sorted arrayTypeScript
function removeDuplicates(nums: number[]): number {
  let write = 1;
  for (let read = 1; read < nums.length; read++) {
    if (nums[read] !== nums[read - 1]) {
      nums[write] = nums[read];
      write++;
    }
  }
  return write;
}
TimeO(n)SpaceO(1)

Pattern 3: Fast and slow pointersPattern

One pointer moves one step at a time, the other moves two. It is used for cycle detection (Floyd's algorithm) and for finding the middle of a linked list: when the fast pointer reaches the end, the slow one is halfway.

320-4cycleslowfastThe tail links back to node 2. Inside a loop, fastgains one node on slow each step, so they must meet.
DiagramA linked list with a cycle.
Detect a cycle in a linked listTypeScript
function hasCycle(head: ListNode | null): boolean {
  let slow = head, fast = head;
  while (fast && fast.next) {
    slow = slow!.next;
    fast = fast.next.next;
    if (slow === fast) return true;
  }
  return false;
}
TimeO(n)SpaceO(1)

When to use two pointersWhen to use

The input is sortedThe opposite-ends pattern needs it to know which pointer to move.
You compare elements from different parts of the array
The problem is about pairs, triplets or subarrays
You need to find a cycle in a linked list or array
You need to partition an array in placeFor example, moving all zeros to the end.
If the problem says…TryWhy
“sorted array”, “pair with sum”Opposite endsThe sum tells you which side to shrink.
“in place”, “remove”, “O(1) extra space”Same directionread scans, write keeps what survives.
“linked list”, “cycle”, “middle”Fast and slowDifferent speeds reveal loops and midpoints.

Common mistakesPitfalls

Not sorting firstThe opposite-ends pattern only works on sorted input.
Off-by-one when the pointers meetleft < right and left <= right behave differently. Decide whether the same element can be used twice.
Using two pointers on unsorted dataWithout sorted order you cannot tell which pointer to move.
Confusing it with sliding windowTwo pointers compare single elements; a sliding window keeps a whole subarray.
Not handling duplicatesIn problems like 3Sum, skip repeated values or you will return the same triplet twice.

How to explain it in the interviewIn the interview

Interviewers want to hear why moving a pointer is safe, not just that you moved it. Say the rule out loud:

Frequently asked questionsFAQ

When should I use two pointers instead of a hash map?

Use two pointers when the input is sorted or when the problem only compares elements at two positions, because both pointers move in a single pass. A hash map is better when the array is unsorted and you need lookups of previously seen values, such as finding a pair that sums to a target. Two pointers uses O(1) extra space; a hash map uses O(n).

Does the two pointers technique require the input to be sorted?

Only the opposite ends pattern requires sorted input, because the algorithm decides which pointer to move by comparing the current sum against the target. The same direction and fast/slow patterns do not need sorted data, since they compare neighbors or advance at different speeds. Sort first when the problem allows O(n log n) preprocessing and then a linear scan.

How does Floyd's cycle detection algorithm find a cycle in a linked list?

Floyd's algorithm moves one pointer one node at a time and a second pointer two nodes at a time. If the list has a cycle, the fast pointer keeps lapsing the slow one and they eventually reference the same node, which proves a cycle exists. If the fast pointer reaches the end of the list first, there is no cycle. Both the time and extra space cost O(1).

Now explain two pointers to me out loud

I'll give you interview problems and ask follow-ups, like a real interviewer.

Practice with Alex

Keep readingKeep reading

Ready to practice?

Reading is step one. Saying it out loud is step two.

Start a mock interview with Alex, get pushed on the parts you skip, and see your hiring signal right after.