Read the constraints first: how I pick the pattern in under 2 minutes
A cheat sheet from six years of mock interviews. Constraints, keywords, and a template for each pattern, including the sliding window everybody gets wrong.
Contents
Most people read the story in a problem and skip the constraints. The story is decoration. The constraints tell you the complexity you are allowed, and the complexity tells you the pattern. This is the routine I use, and the one I have been teaching in mocks for six years.
Step 1: constraints → your budget
Rough rule: a judge does about 10^8 simple operations per second in C++ or Java. So:
- n ≤ 20: exponential is fine. Backtracking, bitmasks. O(2^n · n).
- n ≤ 500: O(n³) works. Interval DP, Floyd-Warshall.
- n ≤ 5,000: O(n²) works. Most 2D DP.
- n ≤ 2 × 10^5: you need O(n log n) or O(n). Sorting, two pointers, sliding window, heaps, binary search, monotonic stack.
- n ≤ 10^7 or more: O(n) with a small constant, or maths.
- Values up to 10^9 and the question says "minimum possible" or "maximum possible": binary search on the answer, very likely.
Edit, after a fair correction in the comments: in Python, think 10 to 50 times fewer operations per second. n log n at 2 × 10^5 is fine, but n² at 5,000 can already be tight.
Write the budget at the top of your page before anything else: "n = 10^5 → n log n". It changes how you think for the next 40 minutes.
Step 2: keywords → pattern
- "sorted", "pair", "triplet" → two pointers
- "contiguous subarray / substring" + "longest / shortest / at most / at least" → sliding window
- "next greater / next smaller", "span", "histogram" → monotonic stack
- "minimize the maximum", "finish within D days" → binary search on the answer
- "k largest", "k closest", "running median" → heap
- "number of ways", "minimum cost to reach" with choices at every step → DP
- shortest path in a grid, every move costs the same → BFS. Different non-negative costs → Dijkstra
- "order", "prerequisites", "dependencies" → topological sort
- "groups", "connected", merging things as you go → DSU (union find)
- "subarray sum equals k" and the array can have negatives → prefix sum + hashmap
- range sums with updates in between → Fenwick tree / segment tree (added after a comment, rare in SDE-1 interviews, common in some OAs)
Step 3: the sliding window template
This is the one people get wrong most, so here is the full template. Problem: the longest substring with at most k distinct characters.
int longestAtMostK(String s, int k) {
int[] freq = new int[128];
int distinct = 0, best = 0, left = 0;
for (int right = 0; right < s.length(); right++) {
if (freq[s.charAt(right)]++ == 0) distinct++; // grow the window
while (distinct > k) { // shrink until valid again
if (--freq[s.charAt(left)] == 0) distinct--;
left++;
}
best = Math.max(best, right - left + 1); // window is valid here
}
return best;
}
Dry run, s = "eceba", k = 2:
- right=0 'e': distinct 1, best 1
- right=1 'c': distinct 2, best 2
- right=2 'e': distinct 2, best 3 ("ece")
- right=3 'b': distinct 3, too many. Drop 'e' (still one 'e' left), left=1. Drop 'c', distinct 2, left=2. Window "eb".
- right=4 'a': distinct 3. Drop 'e', distinct 2, left=3. Window "ba".
Answer 3. The reason it is O(n): left only ever moves forward, so each character enters once and leaves once.
Two things that make this template powerful:
- "Exactly k" questions: exactly(k) = atMost(k) - atMost(k - 1). Write atMost once, call it twice. Many people never see this trick and struggle for an hour.
- Why it breaks with negative numbers: the window logic assumes that removing an element from the left makes the sum smaller. With negatives, removing -3 makes the sum bigger. So for "subarray sum equals k" with negatives, use prefix sums instead:
int subarraySum(int[] a, int k) {
Map<Integer, Integer> seen = new HashMap<>();
seen.put(0, 1); // empty prefix
int sum = 0, count = 0;
for (int x : a) {
sum += x;
count += seen.getOrDefault(sum - k, 0);
seen.merge(sum, 1, Integer::sum);
}
return count;
}
Step 4: the 2-minute routine
- Read the constraints. Write the budget at the top.
- Underline the keywords.
- Say the brute force out loud in one sentence.
- Ask: what work is the brute force repeating? That repeated work is exactly what the pattern removes.
- Only then start coding.
Step 4 is the important one. Two pointers removes re-checking pairs you already know are useless. Sliding window removes re-counting the same window. Monotonic stack removes re-scanning to the right. Binary search on the answer removes trying every candidate. Every pattern is a way of not repeating work.
This is not a list to memorise. It is a list to check yourself against after you have solved about 150 questions properly. Ghabrao mat.
Time to read this post: O(1). Time to make it automatic: about 150 well-revised questions.
Written by
Nikhil Sharan
I teach DSA and system design on YouTube (Two Pointers, 1.2M). Ex-SDE at two product companies, now teaching full time. Dry run everything. No paid course here, only free stuff and honest opinions.
Get the best of #interview_horror weekly
One email each Monday with the most useful posts. No spam; unsubscribe in one click.
Comments
Sign in to join the conversation.
Sign in to comment