DSA Roadmap/Interview Foundations

The Problem-Solving Framework & Interview Communication

A repeatable process for tackling a problem you've never seen, and how to narrate it so the interviewer can actually evaluate you.

!!1/5Theory: 1h2 problems

Why interviewers care about process, not just the answer

A Senior candidate is expected to arrive at a working, reasonably-optimal solution and to make their thinking legible along the way. Two candidates who both pass all test cases can get very different verdicts if one of them thought out loud in a structured way and the other stared silently and then typed. This subtopic gives you that structure so it becomes automatic, freeing up mental bandwidth for the actual algorithm.

The framework: U-M-P-I-R-E (or your own variant)

This acronym (popularized by interview-prep resources like Tech Interview Handbook and various university interview courses) is a good scaffold. Adapt the names, keep the steps:

  1. Understand — restate the problem in your own words. Ask clarifying questions.
  2. Match — does this resemble a known pattern (two pointers, sliding window, DP, etc.)?
  3. Plan — sketch the approach in plain English or pseudocode before writing real code.
  4. Implement — write clean code, narrating non-obvious decisions as you go.
  5. Review — re-read your code, trace through an example by hand.
  6. Evaluate — state time/space complexity, discuss trade-offs and possible follow-ups.

1. Understand — the questions that matter

Don't ask questions for the sake of it; ask ones that could change your approach:

  • Input shape & constraints: What's the input size (n)? This directly tells you the target complexity (see the Big-O subtopic). Can the array be empty? Can it contain duplicates, negatives, or be unsorted when you'd expect sorted?
  • Output contract: Return the answer, or the indices, or modify in place? What if there are multiple valid answers — any of them, or a specific one (e.g. lexicographically smallest)?
  • Edge cases that change the model: empty input, single element, all-identical elements, negative numbers, integer overflow (less relevant in Python, very relevant in Java/C++).

A strong habit: restate the problem back to the interviewer in one or two sentences before doing anything else. This alone catches a large fraction of misunderstandings early, when they're cheap to fix.

2. Match — build a mental "pattern index"

As you go through this roadmap, you're explicitly building this: a mental table of "if the problem looks like X, try pattern Y." Some high-signal triggers:

  • "Contiguous subarray/substring" + constraint on sum/count/uniqueness → Sliding Window.
  • Sorted array, or "pair/triplet that sums to target" → Two Pointers or Binary Search.
  • "Number of ways to..." / "minimum/maximum ... given choices" with overlapping subproblems → Dynamic Programming.
  • "Next greater/smaller element", "span", "histogram" → Monotonic Stack.
  • Graph-shaped relationships (even if not phrased as a graph — e.g. "rooms connected by doors") → BFS/DFS/Union-Find.

You will not have full pattern recognition after this one subtopic — it's built cumulatively as you go through the rest of the roadmap. Revisit this section after finishing a few topics; it will read very differently.

3. Plan — always brute force first, then optimize out loud

A structure that works well under pressure:

  1. State the naive/brute-force approach and its complexity, even if you won't code it. This proves you can always produce a correct answer, and it's often the starting point for finding the optimization (ask: "what is the brute force redoing unnecessarily?").
  2. Identify the bottleneck (usually a repeated linear search, recomputation, or sort).
  3. Propose the optimization and its new complexity, and get a nod from the interviewer before coding. This is the single best way to avoid coding for 15 minutes down the wrong path.

When there are multiple inputs: optimize against the dominant dimension

Many problems aren't "one n" — they have two or more inputs with independent sizes (a grid and a word list, an array and a stream of queries, a graph and a batch of operations). Before committing to a direction, split total cost into preprocess + search and ask which term actually dominates given the stated constraints:

QuestionWhy it matters
What are the separate size variables? (rows×cols, W words, Q queries, …)You can't pick an approach from a single n
Which side is bounded by constraints, and which can grow arbitrarily?A 3×3 board caps path count; a million-word dictionary does not
What gets built once vs. scanned on every query?Preprocessing the wrong side still loses if you iterate the other side in full
Can search prune early, or must it touch everything?A trie during DFS prunes; filter(all_words) does not

The habit: name both dimensions out loud, estimate each term's order of growth, then preprocess the side that is smaller or more reusable and drive search from the side that prunes.

Word Search II is the textbook case. Two natural directions:

  • Trie from words → DFS the board, pruning when the trie has no next character. Preprocess: O(total chars in words). Search: O(board paths that match trie) — never scans the full word list.
  • Trie/paths from the board → check words, which can win when the grid is tiny and the dictionary is enormous — but only if you enumerate board paths (bounded by grid size) and look up in a hash set, not filter over every word.

Neither direction is universally right. The wrong move is picking one by reflex ("always build the trie from words") without checking which dimension the constraints actually favor.

This same lens shows up everywhere:

  • Precompute once, query many — prefix sums, sorted indices, adjacency lists: pay the setup cost on the structure you'll reuse, not on every lookup.
  • Batch vs. online — if queries arrive one at a time, a structure built from all queries upfront may be wrong; if all queries are known, batch preprocessing may dominate.
  • Space–time across inputs — sorting the smaller of two arrays for a merge-style join; indexing the dictionary, not the document, when one is orders of magnitude larger.

A one-line version to say in an interview: "We have two size parameters here — I'll state the cost of each approach in both and pick the one whose dominant term matches the constraints." That single sentence signals Senior-level complexity reasoning even before you write code.

Cap your work using a constraint-derived bound

A separate but equally high-leverage habit: when a loop's natural upper bound is "everything so far" (stream length, number of active states, full array), check whether the problem constraints impose a tighter cap that makes the bound a constant.

Ask: "What's the maximum meaningful window I ever need to consider?"

Problem shapeNaive boundConstraint-derived cap
Suffix match in a streamO(stream length) per queryO(max word length) — no match can be longer than the longest dictionary word
Path on a grid without revisitingO(4^stream_len)O(rows × cols) — can't visit more cells than exist
Subarray sum with bounded valuesO(n²) all pairsO(value range) or O(target / min element) when values are small integers
K closest pointsO(n log n) sort allO(k log k) when k ≪ n

Stream of Characters (in the Tries topic) is the clean example. A naive approach tracks every prior stream position as a separate trie walk — cost grows with query count Q. But no dictionary word is longer than max_len, so any suffix match need only look back max_len characters. Per-query cost drops from O(Q) to O(max_len) — and on LeetCode that's ≤ 200, i.e. a fixed constant regardless of how many queries arrive.

The optimization isn't a new data structure — it's reading the constraints and refusing to iterate past what they allow. State it explicitly: "I only need the last L characters where L is the longest word, so this loop is O(L) not O(stream length)."

This pairs naturally with the multi-input analysis above: constraints often tell you which dimension is actually bounded vs. which one only looks unbounded in the brute-force formulation.

4. Implement — code like it will be read, because it will be

  • Use meaningful variable names (left/right, not i/j for two pointers with distinct roles).
  • Write helper functions for logically distinct chunks instead of one giant function — it makes your code easier to reason about and easier for you to debug live.
  • Narrate non-obvious lines ("I'm using a monotonic decreasing stack here so that...").
  • It's fine to leave a # TODO: handle empty input and come back to it — don't let edge cases derail your momentum on the core logic.

5. Review — trace before you claim it's done

Before declaring victory:

  • Manually trace through the example the interviewer gave you (or a small one you construct), updating your variables on paper/in the editor.
  • Explicitly check your edge cases list from step 1: empty input, size-1 input, duplicates, extremes.
  • Look for off-by-one errors around loop bounds and pointer initialization — the single most common source of small bugs in interview code.

6. Evaluate — close the loop

  • State time and space complexity precisely (see the Big-O subtopic for how).
  • Proactively mention trade-offs: "this trades O(n) extra space for O(n) time; if memory were constrained we could do it in O(1) extra space with an O(n log n) approach by sorting first."
  • If asked "can you do better," don't panic — it's often an invitation to discuss a known alternative, not proof your answer was wrong.

Communication habits that read as "senior" (and mid-2026 context)

  • Think out loud, always — silence is the hardest thing for an interviewer to grade. A partially-wrong idea said out loud is more useful to your evaluation than a correct one arrived at silently.
  • State assumptions explicitly and ask before assuming ("I'll assume the array is 0-indexed and can contain duplicates — is that right?").
  • Handle being wrong gracefully. If the interviewer points out a bug or edge case you missed, treat it as new information, not a personal failure — narrate your correction process.
  • Several FAANG-level companies have introduced AI-assisted coding rounds in their 2026 loops alongside the traditional round. The skills that make you strong in a classic round — structured thinking, clear communication, precise complexity reasoning, rigorous self-review — are the same skills that make you good at directing and verifying AI-generated code. Building them solidly here pays off in both formats.

A worked mini-example of the narration (illustrative, not a specific problem)

"So we need to find [restate problem]. Let me confirm: the array can have duplicates and is unsorted, correct? ... Okay. The brute force would be to check every pair, which is O(n²) — given n can be up to 10^5, that's too slow, so I want O(n) or O(n log n). Since we care about pairs and lookups, I'll try trading space for time with a hash set: as I scan once through the array, I check if the complement is already in the set... [continues implementing] ...Let me trace this on [2, 7, 11, 15] target 9: ... looks right. Edge cases: empty array returns none, and I should confirm what to return if no pair exists. Time complexity O(n), space O(n) for the set."

Internalize this rhythm. It will apply, almost verbatim, to a large fraction of the problems in this roadmap.

Further Resources (Optional)

Practice Problems

Interview relevancy:!!!Critical — must-have!!Important — highly recommended!Good to have~Niche — rarely asked