DSA Problem-Solving Patterns: A Complete Overview
A problem-solving pattern is a reusable shape of solution that recurs across hundreds of different-looking problems. Once you can match a new problem to a pattern, you stop solving from scratch and start adapting a template you already trust. This page is the map: it names the major patterns, tells you the signal in a problem statement that triggers each one, and links to a dedicated recap page for every pattern.
Think of patterns as the difference between “I’ve never seen this” and “this is just two-sum on a sorted array.” The problems are infinite; the patterns are few.
How to recognize a pattern
Most patterns reveal themselves in the input shape, the thing being asked, and the target complexity. Train yourself to read a problem and ask three questions:
- What is the input? (sorted array? linked list? grid? string? a numeric range?)
- What am I optimizing? (a contiguous chunk? a pair? a count of arrangements? a min/max?)
- What complexity is implied? (an
O(n log n)budget screams sorting or binary search;O(n)over a contiguous range screams sliding window.)
The table below is your cheat sheet.
| Pattern | Signal in the problem | Typical complexity | Recap page |
|---|---|---|---|
| Two Pointers | Sorted array/string; find a pair/triplet; reverse or partition in place | O(n) time, O(1) space | Two Pointers |
| Sliding Window | Contiguous subarray/substring; “longest/shortest/at most k” | O(n) time, O(1)–O(k) space | Sliding Window |
| Fast & Slow Pointers | Linked list or sequence; cycle, middle, or nth-from-end | O(n) time, O(1) space | Fast & Slow Pointers |
| Binary Search | Sorted data, or a monotonic yes/no over a numeric answer range | O(log n) per search | Binary Search |
| Backtracking | Generate all subsets/permutations/combinations; constraint puzzles | Exponential (pruned) | Backtracking |
| Dynamic Programming | Overlapping subproblems + optimal substructure; count/min/max of choices | Often O(n·m) | Dynamic Programming |
A worked recognition example
Consider: “Given a sorted array, return two indices whose values sum to a target.” The word sorted plus find a pair points straight at two pointers — walk one pointer from each end, moving inward based on whether the current sum is too big or too small. Here is the template that pattern produces:
#include <vector>
// Two pointers on a sorted array: find a pair summing to target.
std::vector<int> twoSumSorted(const std::vector<int>& a, int target) {
int lo = 0, hi = (int)a.size() - 1;
while (lo < hi) {
int sum = a[lo] + a[hi];
if (sum == target) return {lo, hi};
if (sum < target) lo++; // need a bigger sum
else hi--; // need a smaller sum
}
return {-1, -1}; // no pair found
}
// Two pointers on a sorted array: find a pair summing to target.
int[] twoSumSorted(int[] a, int target) {
int lo = 0, hi = a.length - 1;
while (lo < hi) {
int sum = a[lo] + a[hi];
if (sum == target) return new int[]{lo, hi};
if (sum < target) lo++; // need a bigger sum
else hi--; // need a smaller sum
}
return new int[]{-1, -1}; // no pair found
}
// Two pointers on a sorted array: find a pair summing to target.
function twoSumSorted(a, target) {
let lo = 0, hi = a.length - 1;
while (lo < hi) {
const sum = a[lo] + a[hi];
if (sum === target) return [lo, hi];
if (sum < target) lo++; // need a bigger sum
else hi--; // need a smaller sum
}
return [-1, -1]; // no pair found
}
# Two pointers on a sorted array: find a pair summing to target.
def two_sum_sorted(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 # need a bigger sum
else:
hi -= 1 # need a smaller sum
return [-1, -1] # no pair found
For beginners: You don’t need to memorize every pattern at once. Learn one pattern, solve five problems with it, and it becomes automatic. The signal column above is what you scan first when reading any new problem.
Where patterns connect to the core topics
Patterns aren’t separate from the data structures — they grow out of them. The two-pointers pattern is the searching topic’s two-pointers technique. The fast & slow pattern is the linked-list topic’s fast & slow pointers. The binary-search pattern generalizes binary search into binary search on the answer. Backtracking is structured recursion, and DP patterns build on the dynamic programming topic.
Going deeper: Many hard problems are combinations — e.g. binary search the answer, then verify each candidate with a greedy or sliding-window scan. Recognizing the outer pattern first, then the inner one, is how experienced solvers decompose intimidating questions.
How to use the rest of this section
Each following page is a focused recap: the signal, a reusable 4-language template, the gotchas, and links to the topic pages and exercises where you can drill it. Read them in order, or jump to whichever pattern a problem in front of you seems to need.
Next: start with the two-pointers pattern.