The Two Pointer Technique is an efficient programming pattern that uses two variables (pointers or indices) to traverse a linear data structure—like an array, string, or linked list—usually reducing time complexity from O(n²) to O(n)
Prerequisites
Standard two-pointer techniques (such as opposite-ends convergence) require strict management to prevent infinite loops and index out-of-bounds errors.
- Sorted
- Most standard two-pointer problems (e.g., opposite-ends convergence) require the underlying data structure to be sorted.
- Pointer Placement
- Initialize pointers at boundaries (
left = 0,right = arr.length - 1).
- Initialize pointers at boundaries (
- Critical Guardrails
- Bounds Check
- Always enforce
left < right(or valid index boundaries) in your loop condition to preventArrayIndexOutOfBoundsException.
- Always enforce
- Infinite Loop Prevention
- Ensure every branch inside your loop explicitly modifies at least one pointer (
left++,right--, or both) so the pointers continuously move toward convergence.
- Ensure every branch inside your loop explicitly modifies at least one pointer (
- Bounds Check
Code Example: Two-Pointer Array Reversal
public void reverseArray(int[] arr) {
int left = 0;
int right = arr.length - 1;
// Guard condition prevents out-of-bounds and handles termination
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
// Explicit movement prevents infinite loops
left++;
right--;
}
}When to Use It
graph TD A[Does problem involve a linear structure Array/String/Linked List?] -->|YES| B(Is the data SORTED or order-dependent?) A -->|NO| X[Try other patterns Trees/Graphs] B -->|YES| C(Do you need to find a PAIR, TRIPLET, or BOUNDARIES?) B -->|NO| D(Do you need to check for CYCLES, find a MIDDLE, or COMPRESS IN-PLACE?) C -->|YES| E[CONVERGING POINTERS Left & Right] C -->|NO| F[SLIDING WINDOW Subarrays] D -->|YES| G[FAST & SLOW / SAME DIRECTION] D -->|NO| Y[Try Hash Maps, Sorting, or Brute Force] style E fill:#003366,stroke:#333,stroke-width:2px,color:#fff style F fill:#003366,stroke:#333,stroke-width:2px,color:#fff style G fill:#003366,stroke:#333,stroke-width:2px,color:#fff
The data is sorted (or can be easily sorted)
The Intuition: Sorting creates a predictable environment. If you want to change the value of your current combination, you know exactly which direction to move.
- Example: If your current sum is too low, you move the
leftpointer forward to get a larger number. If the sum is too high, you move therightpointer backward to get a smaller number.
You are optimizing a brute-force O(n²) nested loop
The Intuition: If your first thought is to use an outer loop
iand an inner loopjto scan through pairs or subarrays, you can almost always collapse them into a single loop using two pointers.
- Example: Instead of checking every pair for
target_sum, use one pointer at the start and one at the end, reading them simultaneously to cut down the search space dynamically.
You need to modify an array in-place (without extra space)
The Intuition: You need to rewrite parts of the array while preserving or reading other parts. One pointer keeps track of where the next valid element should be written, while the other pointer scans ahead looking for it. This allows you to manage operations within the same memory block, keeping space complexity to O(1).
- Example: When removing duplicates or shifting zeros, the
writepointer waits until thereadpointer finds a non-duplicate/non-zero element.
The problem involves linear travel with linked structures
The Intuition: You cannot access elements by an index, so you must use relative distance or relative speeds to figure out structure positions.
- Example: Moving one pointer twice as fast as the other will naturally land the slower pointer exactly at the midpoint when the fast one hits the end.
The 5 Structural Strategy Variants
Opposite Ends (Converging Pointers)
Pointers start at the left (0) and right (n-1) boundaries and move toward the center.
- Two Sum II - Input Array Is Sorted: Find two numbers that add up to a target sum in a sorted array.
- Valid Palindrome: Check if a string reads the same forward and backward after cleanup.
- 3Sum / 4Sum: Find all unique triplets or quadruplets that sum up to a specific value.
- Container With Most Water: Find two lines that form a container containing the most water.
- Trapping Rain Water: Compute how much water an elevation map can trap after raining.
- Boats to Save People: Find the minimum number of boats required to carry everyone given a weight limit.
The two-pointer pattern you just used (moving inward from both ends with i and j) is extremely powerful and unlocks a whole family of classic string and array problems.
Here are some great LeetCode questions that follow this exact same mindset:
1. Direct Variations (In-Place String/Array Modification)
- Valid Palindrome II (LeetCode 680):
- The Twist: You are allowed to delete at most one character to make a string a palindrome.
- Why it fits: You use your standard two-pointer check, but when
carr[i] != carr[j], you branch out and check both sub-segments (skipping eitheriorj) to see if either forms a valid palindrome.
- Reverse Words in a String III (LeetCode 557):
- The Twist: Reverse the characters of each word in a sentence while maintaining whitespace and initial word order.
- Why it fits: You scan for spaces to find word boundaries and then apply a local two-pointer swap on the character array for each individual word.
2. The Classic Two-Pointer Core (Passing the Same Template)
- Two Sum II - Input Array Is Sorted (LeetCode 167):
- The Twist: Find two numbers in a sorted array that add up to a specific target.
- Why it fits: Instead of comparing characters for equality, you compare the sum of elements at
iandjagainst your target, movingi++if the sum is too small orj--if it’s too large.
- Container With Most Water (LeetCode 11):
- The Twist: Find two lines that together with the x-axis form a container, holding the most water.
- Why it fits: You place pointers at the absolute left and right ends, calculate the area, and move the pointer pointing to the shorter line inward to try and find a taller boundary.
- 3Sum (LeetCode 15):
- The Twist: Find all unique triplets in an array that sum to zero.
- Why it fits: You fix one number with an outer loop and then unleash the standard inward-moving two-pointer approach on the remaining subarray. Whenever you see a problem asking you to search or manipulate elements from both ends moving toward the center, or dealing with a sorted/constrained array, this two-pointer layout is almost always your best friend.
Same Direction (Fast & Slow / Reader & Writer)
Both pointers start from the beginning, but one moves faster or under different conditions than the other.
- Remove Duplicates from Sorted Array: Modify a sorted array in-place so each unique element appears only once.
- Move Zeroes: Shift all
0s to the end of an array while maintaining the relative order of non-zero elements. - Sort Colors (Dutch National Flag): Sort an array containing
0s,1s, and2s in a single pass using multiple pointer boundaries. - Is Subsequence: Determine if a string is a subsequence of another string.
Fast & Slow (Linked Lists / Cycles)
Also known as Floyd’s Tortoise and Hare algorithm. Pointers move at different speeds (slow = slow.next, fast = fast.next.next).
- Linked List Cycle Detection: Check if a linked list has a loop/cycle in it.
- Middle of the Linked List: Find the middle node of a single linked list.
- Remove Nth Node From End of List: Use a gap of
nelements between two pointers to locate and remove the targeted node from the end. - Happy Number: Determine if a number is “happy” by using cycle detection logic on the sum of squares of its digits.
Two Independent Arrays / Lists
One pointer is assigned to track the progress of each separate data structure.
- Merge Sorted Array: Merge two pre-sorted arrays into one single sorted array in-place.
- Intersection of Two Arrays II: Find the common elements overlapping across two distinct arrays.
Sliding Window Pattern (Extension of Two Pointers)
The two pointers act as the dynamic start and end boundaries of a subsegment/window.
- Longest Substring Without Repeating Characters: Find the length of the longest unique substring.
- Minimum Size Subarray Sum: Find the minimal length of a contiguous subarray whose sum is greater than or equal to a target.
Quick Comparison Matrix
| Strategy | When to use it | Visualizing the movement |
|---|---|---|
| Converging | Finding pairs/triplets in sorted arrays, or checking symmetric structures. | [➔ ➔] (Move toward each other) |
| Fast & Slow | Linked Lists (cycles, midpoints) or detecting repeating patterns. | [➔ ➔ ] (One moves at 1x speed, one at 2x) |
| Same Direction | In-place updates, space-saving compression, or building windows. | [➔ ➔ ] (Both move right, but at different paces) |