Use two indices moving toward each other or in the same direction to solve pair and partition problems.
The two-pointer technique uses two index variables that traverse the array — usually one from each end (converging) or both from the start (fast/slow). It reduces O(n²) brute-force pair searches to O(n) by avoiding redundant comparisons.
O(n) — each pointer moves at most n steps
O(1) — no extra space needed
Learn the core patterns in this topic. Each block explains when to use the pattern, the intuition behind it, and a compact code example.
Use this when the array is sorted or when the answer depends on comparing values from both ends
Because the input is ordered, moving one pointer changes the result in a predictable direction. This lets you eliminate many impossible pairs without checking them explicitly.
Problem Two Sum II. Start with one pointer at the beginning and one at the end, compare their sum with the target, and move the pointer that makes the sum closer.
// Converging pointers — Two Sum II (sorted array)
function twoSumSorted(nums, target) {
let left = 0, right = nums.length - 1;
while (left < right) {
const sum = nums[left] + nums[right];
if (sum === target) return [left + 1, right + 1];
if (sum < target) left++;
else right--;
}
return [];
}Use this when two traversals moving at different speeds reveal structure such as a middle node, a cycle, or a repeating state
The slow pointer gives position, while the fast pointer helps detect relative motion. This pattern is especially common in linked lists but also appears in arrays and strings.
Problem Linked List Cycle. Move slow by one step and fast by two steps; if they ever meet, a cycle exists.
// Fast/slow pointers — Linked List Cycle detection
function hasCycle(head) {
let slow = head, fast = head;
while (fast && fast.next) {
slow = slow.next;
fast = fast.next.next;
if (slow === fast) return true;
}
return false;
}Use this when you need to rearrange elements in-place while preserving a region of already processed values
One pointer reads the current element, and another pointer marks where the next kept element should be written. This avoids extra arrays and makes in-place partition problems very manageable.
Problem Move Zeroes. Scan with the fast pointer, and each time you see a non-zero value, swap it into the next write position.
// Read/write partition — Move Zeroes in-place
function moveZeroes(nums) {
let slow = 0;
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== 0) {
[nums[slow], nums[fast]] = [nums[fast], nums[slow]];
slow++;
}
}
}Use this when a sorted array contains repeated values and you want to keep only one copy or a limited number of copies
The sorted order ensures equal values are adjacent, which makes comparison against the last kept value enough. This is a classic in-place array pattern.
Problem Remove Duplicates from Sorted Array. Keep a write pointer for the last unique value and copy forward only when a new unique value appears.
// Duplicate compression — Remove Duplicates from Sorted Array
function removeDuplicates(nums) {
if (nums.length === 0) return 0;
let slow = 0;
for (let fast = 1; fast < nums.length; fast++) {
if (nums[fast] !== nums[slow]) nums[++slow] = nums[fast];
}
return slow + 1;
}Use this as a decision rule before applying two pointers
If the array is already sorted, two pointers often works directly. If it is not sorted but order does not matter, sorting first may unlock a cleaner solution. This mindset helps you recognize when a brute-force pair or triplet search can be improved.
Problem 3Sum. Sort the array first, then fix one value and run a two-pointer search on the remaining suffix.
// Sorted input recognition — 3Sum with sort + two pointers
function threeSum(nums) {
nums.sort((a, b) => a - b);
const result = [];
for (let i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] === nums[i-1]) continue;
let left = i + 1, right = nums.length - 1;
while (left < right) {
const sum = nums[i] + nums[left] + nums[right];
if (sum === 0) {
result.push([nums[i], nums[left], nums[right]]);
while (left < right && nums[left] === nums[left+1]) left++;
while (left < right && nums[right] === nums[right-1]) right--;
left++; right--;
} else if (sum < 0) left++;
else right--;
}
}
return result;
}Use this when the problem involves triplets or more complex combinations but still has an ordered structure
Fix one element, reduce the remaining work to a simpler two-pointer problem, and repeat. This is a very common interview reduction technique because it turns O(n³) brute force into O(n²).
Problem 3Sum. Fix index i, then use left and right pointers on the subarray after i to find pairs that complement nums[i].
// Fix one, search the rest — Container With Most Water
function maxArea(height) {
let left = 0, right = height.length - 1, best = 0;
while (left < right) {
const area = (right - left) * Math.min(height[left], height[right]);
best = Math.max(best, area);
if (height[left] < height[right]) left++;
else right--;
}
return best;
}