Interview Prep And Revision
Mock Interview-Style Questions
An interviewer is evaluating your process, not just your final code — they can't see how you think unless you narrate it. Silently producing a correct optimized
Jr Codex DSA Notes
Level: Advanced Prerequisites: Chapter 2 Time to complete: ~30 minutes
Table of Contents
- Why How You Talk Matters as Much as the Code
- The Four-Step Shape of a Strong Answer
- Mock Dialogue 1: Longest Palindromic Substring
- Mock Dialogue 2: Course Schedule
- Phrases That Signal Strength (and Ones to Avoid)
- Summary & Next Steps
1. Why How You Talk Matters as Much as the Code
An interviewer is evaluating your process, not just your final code — they can't see how you think unless you narrate it. Silently producing a correct optimized solution is actually a weaker signal than talking through a mediocre brute force, clarifying assumptions, and reasoning your way to the optimization out loud. This chapter is about the second thing.
2. The Four-Step Shape of a Strong Answer
- Clarify — ask about edge cases, input constraints, and any ambiguity before writing anything. This shows rigor and often reveals a simplification.
- Brute force first — state an obviously-correct, possibly slow approach and its complexity. This proves you understand the problem and gives you (and the interviewer) a baseline.
- Optimize — explicitly name why the brute force is slow (usually: redundant work, a hidden loop, or a missed data structure — recall Module 1's traps), then apply the relevant pattern from Chapter 1's cheat sheet.
- State final complexity — time and space, unprompted. Don't make the interviewer ask.
3. Mock Dialogue 1: Longest Palindromic Substring
Interviewer: "Given a string, find its longest palindromic substring."
Candidate (clarifying): "A palindrome reads the same forwards and backwards — can I assume the string is non-empty, and should I assume there's a unique longest one, or can I return any of them if there's a tie in length?" Interviewer: "Non-empty, ASCII letters only. Any valid longest one is fine."
Candidate (brute force): "The simplest approach is to check every possible substring and test whether it's a palindrome. There are O(n²) substrings, and checking each one for being a palindrome costs up to O(n), so that's O(n³) overall — correct, but slow."
def longest_palindrome_brute(s):
def is_palindrome(sub):
return sub == sub[::-1]
longest = ""
for i in range(len(s)):
for j in range(i, len(s)):
candidate = s[i:j + 1]
if is_palindrome(candidate) and len(candidate) > len(longest):
longest = candidate
return longestCandidate (optimizing): "The slow part is re-checking whole substrings from scratch. A better approach: every palindrome has a center — either a single character (odd length) or a gap between two characters (even length). If I expand outward from each possible center as long as both sides match, I check 2n - 1 centers, and each expansion costs at most O(n) — that's O(n²) total instead of O(n³), and O(1) extra space instead of building new substrings at every step."
def longest_palindrome(s):
def expand_around_center(left, right):
while left >= 0 and right < len(s) and s[left] == s[right]:
left -= 1
right += 1
return s[left + 1:right] # the palindrome found, trimmed back
longest = ""
for center in range(len(s)):
odd = expand_around_center(center, center) # single-character center
even = expand_around_center(center, center + 1) # gap between two characters
longest = max(longest, odd, even, key=len)
return longestCandidate (complexity): "This runs in O(n²) time and O(1) extra space beyond the output — a solid improvement over the brute force's O(n³), and there's a linear-time algorithm (Manacher's) beyond this, but I'd flag that as further optimization only if it's needed here."
4. Mock Dialogue 2: Course Schedule
Interviewer: "There are n courses labeled 0 to n-1. You're given a list of prerequisite pairs [a, b] meaning you must take course b before course a. Determine if it's possible to finish all courses."
Candidate (clarifying): "So this is really asking whether the prerequisite graph has a cycle — if course A needs B and B eventually needs A again, it's impossible. Can prerequisites be listed more than once, or is self-referential input possible (a course depending on itself)?" Interviewer: "Assume no duplicate edges, and no self-loops guaranteed — you should handle that case defensively."
Candidate (brute force): "For every course, I could try to do a full DFS from it, following prerequisites, and check if I ever come back to where I started — but repeating that DFS from every node is redundant work, since a node's reachability doesn't change between DFS runs. That's O(V × (V + E)) in the worst case."
Candidate (optimizing): "This is really a directed-graph cycle detection problem — from Module 9. I'll build an adjacency list from the prerequisite pairs, then run a single DFS pass, tracking nodes currently 'in progress' (on the current recursion path) versus fully 'done.' If I ever reach a node that's still in progress, that's a cycle."
def can_finish(num_courses, prerequisites):
graph = {i: [] for i in range(num_courses)}
for course, prereq in prerequisites:
graph[course].append(prereq)
in_progress = set()
done = set()
def has_cycle(course):
if course in done:
return False # already fully explored, no cycle found through it
if course in in_progress:
return True # back edge — found a cycle
in_progress.add(course)
for prereq in graph[course]:
if has_cycle(prereq):
return True
in_progress.remove(course)
done.add(course)
return False
for course in range(num_courses):
if has_cycle(course):
return False
return TrueCandidate (complexity): "Each node is visited once overall thanks to the done set preventing re-exploration, and each edge is examined once — so this is O(V + E) time, O(V) space for the recursion stack and the two tracking sets. That's the standard complexity for a full graph traversal, and it's optimal since you have to look at every prerequisite at least once to be sure."
5. Phrases That Signal Strength (and Ones to Avoid)
Say instead of staying silent:
- "Let me start with a brute force so we have a correctness baseline."
- "The bottleneck here is X — that's why I'm reaching for [hash map / sliding window / heap / DP]."
- "This is O(n) time and O(n) space — the space comes from the [cache / hash set / recursion stack]."
Avoid:
- Jumping straight to the optimized solution with no narration — it looks like memorized code, not reasoning.
- Declaring complexity without justifying it — always name which part of the code produces that bound.
- Staying silent when stuck — narrating "I think this might need [pattern], let me check if the greedy-choice property holds" (Module 10, Chapter 4) shows process even mid-struggle.
6. Summary & Next Steps
Key Takeaways
- Interviews evaluate process as much as the final answer — narrate clarify → brute force → optimize → complexity, every time, even under time pressure.
- Naming why the brute force is slow (before naming the fix) is what actually demonstrates understanding, not the fix itself.
- Both mock dialogues above followed the exact same four-step shape regardless of topic (strings vs. graphs) — that shape, not the specific algorithm, is what to rehearse.
Concept Check
- Why is a narrated brute force generally a stronger opening move than silently jumping to the optimal solution?
- In the Course Schedule dialogue, why are two separate sets (
in_progressanddone) needed instead of just one "visited" set? - Try running the four-step shape yourself, out loud, on one problem from Chapter 2 that you haven't yet revisited.
Next Chapter
→ Chapter 4: Final Revision & Next Steps
Jr Codex — 1-on-1 Personalized Coaching | Back to Module Index