- Use the same six steps every time: Clarify → Examples → Brute force → Optimise → Code → Test. The fixed order keeps you moving when the clever idea has not arrived yet.
- Constraints pick the algorithm: n ≤ 20 exponential is fine, n ≤ 5,000 means O(n²), n ≤ 105 to 106 means O(n log n) or O(n).
- Optimise by naming the bottleneck in your brute force ("I recompute this sum every time") and picking the data structure that removes it.
- Get agreement on the approach before coding. Then test with a dry-run table and edge cases out loud.
- The worked example below (Subarray Sum Equals K) shows the full dialogue, including the clarifying question that rules out the sliding window most people reach for.
Most people who fail coding rounds do not fail because they lack knowledge. They fail because they meet an unfamiliar problem, panic, jump to code with a half-formed idea, and spend the last fifteen minutes debugging something that was never going to work. A fixed procedure fixes that. It turns "I have no idea" into a list of next actions, and it shows the interviewer the problem-solving signal they are actually grading.
This guide gives you that procedure, explains what to do and say in each step, and then runs a complete mock interview on a real problem so you can see the steps working together.
The Six-Step Method at a Glance
| Step | Goal | Output before moving on | Typical time (45-min round) |
|---|---|---|---|
| 1. Clarify | Remove ambiguity | Input types, ranges, edge cases, output format agreed | 2 to 4 min |
| 2. Examples | Understand by hand | 2 to 3 worked examples, including one tricky case | 2 to 4 min |
| 3. Brute force | Guarantee a baseline | Correct naive approach + its complexity | 2 to 3 min |
| 4. Optimise | Reach target complexity | Approach the interviewer agrees with | 5 to 10 min |
| 5. Code | Clean, correct implementation | Complete code with good names | 12 to 18 min |
| 6. Test | Find your own bugs | Dry run + edge cases + final complexity | 4 to 7 min |
These steps are not original to me; versions of them appear in most interview prep material (some call it UMPIRE: Understand, Match, Plan, Implement, Review, Evaluate). What matters is doing them visibly and in order, every time, including in practice.
Step 1: Clarify the Problem Before Anything Else
Restate the problem in one sentence in your own words, then ask about the things that change the algorithm. Not every question is worth asking; ask the ones whose answer would change your approach.
| Question | Why it matters |
|---|---|
| What is the size of n? Range of values? | Sets the target complexity and whether you need long to avoid overflow |
| Can values be negative or zero? | Negatives break sliding window and many greedy ideas |
| Are there duplicates? | Affects hashing, binary search bounds and "distinct" counting |
| Is the input sorted? Can I modify it? | Sorted input suggests two pointers or binary search; sorting in place may be disallowed |
| What should I return if there is no answer? Empty input? | Avoids a wrong sentinel like 0 vs -1 |
| Multiple valid answers: return any or all? | "All" can change output size and complexity |
| Graph: directed? connected? cycles? self-loops? | Picks between BFS, topological sort, union-find |
| Strings: character set? case sensitive? | Fixed-size array vs hash map for counts |
Step 2: Work Through Examples by Hand
Write two or three small inputs and solve them manually, saying what you do. This is where the algorithm usually reveals itself, because your hands do something smarter than brute force without you noticing. Watch what you naturally track.
- One normal case big enough to be non-trivial (6 to 8 elements).
- One edge case: empty, single element, all same, all negative.
- One adversarial case that breaks the obvious idea, if you can think of it. Finding it early saves you from building on a wrong idea.
Agree on the expected output for each with the interviewer. If your example's answer differs from theirs, you have just found a misunderstanding at minute 4 instead of minute 35.
Step 3: State the Brute Force and Its Complexity
Describe the most direct correct solution: try every pair, every subarray, every subset. Give its time and space complexity. You usually do not code it. Its job is threefold:
- It proves you understand the problem.
- It gives you a fallback. A working O(n²) beats a broken O(n).
- It shows where the waste is, which is the starting point for step 4.
Keep it short: "The brute force checks every pair, O(n²) time and O(1) space. With n up to 105 that is 1010 operations, too slow, so let me find the repeated work."
Step 4: Optimise by Attacking the Bottleneck
Do not stare at the problem hoping for inspiration. Point at the specific part of the brute force that costs the most and ask which tool removes it. This table covers most interview problems:
| Bottleneck in brute force | Tool that removes it |
|---|---|
| Inner loop searching for a matching value | Hash map / hash set (O(1) lookup) |
| Recomputing the sum of a range | Prefix sums |
| Checking every pair in a sorted array | Two pointers |
| Recomputing a window as it shifts | Sliding window (non-negative or monotonic condition) |
| Searching a monotonic yes/no condition | Binary search (on index or on answer) |
| Repeatedly finding the min/max | Heap, or monotonic deque for windows |
| "Next greater / previous smaller" scans | Monotonic stack |
| Recomputing the same subproblem in recursion | Memoisation / DP |
| Exploring states, shortest steps | BFS; Dijkstra if weighted |
| Repeated "are these connected?" queries | Union-find |
| Prefix lookups over many strings | Trie |
Two more questions that unlock many problems: "Would sorting help?" (costs O(n log n) but often enables two pointers or greedy) and "What if I process from the right, or fix one element and solve the rest?"
When you have an approach, explain it and get a nod before coding. Say the complexity. If the interviewer asks "can you do better?", it usually means yes; if they say "sounds good, go ahead", start coding.
Step 5: Write Clean Code, Not Fast Code
- Use descriptive names:
prefixSum,seenCount,left, nota,m,t. - Write the skeleton first: function signature, main loop, return. Then fill in the body.
- Extract helpers for distinct pieces (e.g.
isValid(row, col),neighbors(node)). If time is short, leave a well-named stub and say you will fill it. - Narrate intent, not syntax. "Now I store the prefix sum so later indices can look it up" is useful; "now I write a for loop" is noise.
- Handle edge cases explicitly at the top if they are not naturally covered.
Step 6: Test Your Own Code Like a Reviewer
Do not say "I think this works". Prove it. First, read your code once, line by line, looking for off-by-one errors, wrong variable names and missing returns. Then dry-run a small example with a variable table. Finally run through edge cases mentally: empty, single element, duplicates, negatives, overflow at max constraints.
When you find a bug, say "I found a bug here" calmly and fix it. Finding your own bugs is scored positively; interviewers pointing them out is not.
A Full Worked Interview: Subarray Sum Equals K
Here is how the method plays out on LeetCode 560. Read it as a script: the candidate's moves are the point, not just the final code.
Interviewer: Given an integer array
numsand an integerk, return the number of contiguous subarrays whose sum equalsk.
Clarify
Candidate: So I count every pair (i, j) with i ≤ j where nums[i] + ... + nums[j] == k. A few questions. How large can the array be?
Interviewer: Up to 2 × 104. Values between -1000 and 1000, k between -107 and 107.
Candidate: So values can be negative. That matters: a sliding window assumes that growing the window increases the sum, which is false with negatives, so I will not use a window. Overlapping subarrays each count separately? And for an empty array I return 0?
Interviewer: Yes and yes.
Examples
Candidate: Let me take nums = [1, 1, 1], k = 2. Subarrays [1,1] at positions 0-1 and 1-2, so the answer is 2. A trickier one with negatives: [3, 4, -7, 1, 3, 3, 1, -4], k = 7. By hand: [3,4], [3,4,-7,1,3,3], [1,3,3], [3,3,1]. That is 4. Edge case: [5], k = 5 gives 1, and [0, 0], k = 0 gives 3 since [0], [0], [0,0] all count.
Interviewer: Agreed.
Brute force
Candidate: The direct approach: for each start i, extend j to the right keeping a running sum, and count when it equals k. That is O(n²) time and O(1) space. With n = 2 × 104 that is 4 × 108 basic steps in the worst case, borderline. I would like something linear.
Optimise
Candidate: The repeated work is summing ranges. If I define prefix[j] as the sum of the first j+1 elements, then the sum of i..j is prefix[j] - prefix[i-1]. I want that to equal k, so for each j I need the number of earlier prefixes equal to prefix[j] - k. That is a lookup, so I keep a hash map from prefix sum to how many times I have seen it. I seed it with {0: 1} for the empty prefix, so subarrays starting at index 0 are counted. One pass, O(n) time, O(n) space.
Interviewer: Why do you need counts rather than a set?
Candidate: Because with zeros and negatives the same prefix sum can appear several times, and each earlier occurrence gives a different valid start. In [0, 0] with k = 0, prefix 0 appears three times counting the seed.
Interviewer: Good, go ahead.
Code
from collections import defaultdict
def subarray_sum(nums, k):
count = 0
prefix = 0
seen = defaultdict(int) # prefix sum -> number of times seen
seen[0] = 1 # empty prefix, for subarrays starting at 0
for x in nums:
prefix += x
count += seen[prefix - k] # earlier prefixes that leave sum k
seen[prefix] += 1
return count
int subarraySum(const vector<int>& nums, int k) {
unordered_map<long long, int> seen;
seen[0] = 1;
long long prefix = 0;
int count = 0;
for (int x : nums) {
prefix += x;
auto it = seen.find(prefix - k);
if (it != seen.end()) count += it->second;
seen[prefix]++;
}
return count;
}
Candidate (while coding): I look up before inserting the current prefix, otherwise with k = 0 I would count the empty subarray ending here. In C++ I use find instead of seen[prefix - k] so I do not insert useless zero entries.
Test
Candidate: Dry run on [3, 4, -7, 1, 3, 3, 1, -4], k = 7:
| x | prefix | prefix - k | seen[prefix-k] | count | seen after |
|---|---|---|---|---|---|
| 3 | 3 | -4 | 0 | 0 | {0:1, 3:1} |
| 4 | 7 | 0 | 1 | 1 | + 7:1 |
| -7 | 0 | -7 | 0 | 1 | 0:2 |
| 1 | 1 | -6 | 0 | 1 | + 1:1 |
| 3 | 4 | -3 | 0 | 1 | + 4:1 |
| 3 | 7 | 0 | 2 | 3 | 7:2 |
| 1 | 8 | 1 | 1 | 4 | + 8:1 |
| -4 | 4 | -3 | 0 | 4 | 4:2 |
Candidate: Final count is 4, matching my manual answer. Edge cases: empty array never enters the loop, returns 0. [0, 0], k = 0: first 0 sees seen[0] = 1, count 1; second sees seen[0] = 2, count 3. Correct. Overflow: max prefix is 2 × 104 × 1000 = 2 × 107, which fits in an int, but I used long long in C++ anyway. Final complexity: O(n) time, O(n) space for the map.
Interviewer: What if I asked for the longest subarray with sum k instead?
Candidate: Then I store the first index at which each prefix sum appears instead of a count, and for each j take j - firstIndex[prefix - k]. Storing only the first occurrence maximises the length. Still O(n).
Notice what happened: the optimal idea came from step 4's question "what am I recomputing?", the critical correctness detail (no sliding window) came from step 1, and the off-by-one around insert-before-lookup was caught and explained during step 5. None of that needed a flash of genius.
What to Do When You Get Stuck
Getting stuck is normal and interviewers plan for it. What they grade is how you behave while stuck. Work through this list out loud:
- Say where you are. "I have O(n²); the bottleneck is finding the partner element. I am looking for a way to avoid the inner loop."
- Go back to examples. Solve a bigger one by hand and watch what you track mentally.
- Run the pattern checklist. Sort? Hash? Two pointers? Window? Binary search on the answer? Heap? Stack? Prefix sums? Graph? DP? For each, spend ten seconds asking "what would that look like here?"
- Simplify the problem. Solve it for sorted input, for non-negative values, for k = 1, for a tree that is a line. Then generalise.
- Ask a targeted question. "Would it help to think of this as a graph?" is better than "Can I get a hint?" Both are acceptable.
- Use the hint fully. Repeat it in your words and connect it to your approach. Taking a hint well is a positive signal; ignoring it is a negative one.
- Fall back. With about 15 minutes left and no optimal idea, code the brute force cleanly and discuss how you would optimise it. A working, tested solution scores better than an unfinished clever one.
Silence is the real failure mode. If you are thinking, say what you are thinking; the guide on thinking out loud has phrases that keep you talking without sounding scripted.
A 45-Minute Time Budget That Works
| Minute | Activity | Warning sign |
|---|---|---|
| 0 to 5 | Intros (often), problem statement | Long intros eat your time; keep yours to 60 seconds |
| 5 to 10 | Clarify + examples | Still no examples at minute 12 |
| 10 to 18 | Brute force, optimise, agree | Coding with no agreed approach |
| 18 to 35 | Code | Still on line 5 at minute 30 |
| 35 to 42 | Dry run, edge cases, complexity | Saying "I think it works" with no dry run |
| 42 to 45 | Follow-ups, your questions | No time left for questions |
Many Indian product companies (and Google, Microsoft, Amazon India loops) run 45 to 60 minute rounds, sometimes with two problems. With two problems, halve each block and move faster through the brute-force step. Confirm the format with your recruiter; it varies by company and team.
How Interviewers Score You on Each Step
Rubrics differ by company, but most product-company feedback forms cover similar dimensions:
| Dimension | What earns a strong rating | What hurts |
|---|---|---|
| Problem solving | Clarifies, explores options, justifies the choice | Jumps to code, cannot explain why the approach works |
| Algorithms and complexity | Correct Big-O, recognises the right pattern | Wrong complexity, unaware of better options |
| Coding | Clean, idiomatic, readable, few bugs | Messy names, copy-pasted blocks, language misuse |
| Verification | Dry runs, finds own bugs, considers edge cases | Relies on the interviewer to find bugs |
| Communication | Explains reasoning, takes hints well | Long silences, argues with hints |
The six-step method maps directly onto these: steps 1 to 4 produce the problem-solving and complexity signal, step 5 the coding signal, step 6 the verification signal, and doing them all aloud produces the communication signal. If you are getting rejections despite solving problems, this table is usually why; why engineers fail interviews goes through the other common causes.
How to Practise the Method Until It Is Automatic
- Write the steps as comments at the top of your file for the first 30 practice problems:
# clarify, # examples, # brute, # optimise, # code, # test. Fill each one before moving on. - Practise on unseen problems with a timer. Familiar problems train recall, not method. LeetCode contest problems and company-tagged problems you have not solved are ideal.
- Record yourself solving one problem a week out loud. Watching it back is uncomfortable and extremely effective.
- Do mocks with a human. A partner who interrupts with questions forces you to keep the structure under pressure. The mock interview strategy guide covers how to run them.
- Build your pattern vocabulary. Step 4 is only as good as the tools you can name. Work through the core DSA patterns so the bottleneck table above feels obvious.
Frequently Asked Questions
Practise the Method Under Real Pressure
Prepflix mock interviews put this six-step method to work on unseen problems with ex-FAANG interviewers, and give you a written score on each step so you know exactly what to fix.
Explore the Prepflix Course →