Two Pointers
Consider two pointers when sorted order lets you discard candidates, when two ordered streams must be combined, or when an array must be filtered or partitioned in place. Two indices alone do not guarantee a linear algorithm: explain why each move is safe and why neither pointer repeatedly backtracks.
1. Discard Candidates from the Ends
For a sorted array and target sum, start at left=0, right=n-1. If the pair sum is too small, even the largest remaining partner cannot rescue nums[left], so discard it. If too large, even the smallest remaining partner makes nums[right] too large, so discard that endpoint.
Use left < right when a pair must contain two distinct positions. Each step removes one position from consideration: time, extra space. Sorting an unsorted input first adds and may lose original indices; compare a hash-map solution when indices must be returned.
For Container With Most Water, move the shorter wall: with that wall fixed, moving the taller wall inward only reduces width and cannot raise the limiting height. Similar-looking pointer movements need their own justification; sorted order is not the argument here.
For palindromes that ignore punctuation, validate both bounds while skipping characters. An empty or all-punctuation input must terminate without an out-of-bounds read.
2. Recipe: Seeker and Writer
The reference chapter's named recipe separates where to read next from where the next retained value belongs. For deduplicating a sorted array:
def deduplicate(nums):
writer = 0
for seeker in range(len(nums)):
if writer == 0 or nums[seeker] != nums[writer - 1]:
nums[writer] = nums[seeker]
writer += 1
return writer
Before each read, nums[:writer] is the deduplicated result for the processed prefix, and writer <= seeker. Writing cannot overwrite unread input. Compare with the last retained value, since earlier positions may already have changed. The return value is the valid prefix length; the trailing elements are irrelevant. Time is , space , and retained order is preserved.
For Remove Element, change the keep condition to nums[seeker] != target. If output expands, reading and writing from the left may overwrite unread values: Merge Sorted Array instead fills spare capacity from the right, always writing the larger remaining item.
3. Merge, Intersect, or Partition
Two sorted streams: compare their current items and advance the one that can no longer affect the next result. A merge emits the smaller value and later drains the nonempty tail; an intersection emits equal values and advances both. Define whether duplicates are counted or collapsed. Total time is ; output storage is separate.
For two lists of internally disjoint sorted intervals, the current intersection is [max(start1,start2), min(end1,end2)] if its start does not exceed its end. Advance the interval that ends first: it cannot overlap a later interval from the other list. If ends tie, both may advance. See Interval List Intersections.
Three-way partition: maintain < pivot in [0,low), == pivot in [low,scan), unknown values in [scan,high], and > pivot after high. A smaller value swaps to low and advances both low and scan; an equal value advances scan; a larger value swaps with high and only decrements high. Do not advance scan in the last case: the swapped-in value has not been inspected. This gives time and space, usually without stability.
To rotate or exchange adjacent unequal-length blocks A B into B A, reverse A, reverse B, then reverse the whole range. Internal order is restored by the final reversal. The total is time and space; the Prefix-Suffix Swap variation applies this identity.
4. Key Takeaways
- Sorted two-sum discards an endpoint only after ruling out all its remaining partners.
- A writer must not pass unread input; filter left to right, but merge into spare tail capacity right to left.
- After swapping an unknown value from the right side of a partition, inspect it before moving on.
- State whether endpoints are inclusive, positions must differ, and duplicates or original order matter.
Continue to Sliding Windows for contiguous ranges with maintained state, Linked Lists for fast/slow node pointers, and Sorting for merging and partitioning as larger algorithm steps.
Practice Problems
Core Practice
Two Sum II - Input Array Is Sorted
Given a 1-indexed array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number. Let these two numbers be numbers[index1] and numbers[index2] where 1 <= index1 < index2 <= numbers.length.
Remove Duplicates from Sorted Array
Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same. Then return the number of unique elements in nums.
Merge Sorted Array
You are given two integer arrays nums1 and nums2, sorted in non-decreasing order, and two integers m and n, representing the number of elements in nums1 and nums2 respectively.
Dutch Flag Problem
Given an array consisting of letters 'R', 'W', and 'B', sort it in place to put all the 'R' before all the 'W' and all the 'W' before all the 'B'.
Optional Variations (8)
Choose a variation when you want to explore a specific pattern. These are not required before moving to the next topic.
Valid Palindrome
A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.
Container With Most Water
You are given an integer array height of length n. There are n vertical lines drawn such that the two endpoints of the ith line are (i, 0) and (i, height[i]).
Squares of a Sorted Array
Given an integer array nums sorted in non-decreasing order, return *an array of the squares of each number sorted in non-decreasing order*.
Interval List Intersections
You are given two lists of closed intervals, firstList and secondList, where firstList[i] = [start_i, end_i] and secondList[j] = [start_j, end_j]. Each list of intervals is pairwise disjoint and in sorted order.
Parity Sorting
Given an array of integers arr, modify it in place to put all even numbers before all odd numbers. The relative order between even numbers does not matter. Same for the odd numbers.
Quicksort Partition
Given an array of integers arr and a number pivot, modify arr in place using only O(1) extra space so that:
Prefix-Suffix Swap
We are given an array of letters, arr, and a length, n, which is a multiple of 3. The goal is to modify arr in place to move the prefix of length n/3 to the end and the suffix of length n/3 to the beginning.
Shift Word to Back
You are given an array of letters, arr, and a string, word. We know that word appears within arr as a subsequence. Identify the earliest occurrence of word in arr and move all those letters, in order, to the end of arr. You must do this in place.