DAY 29 / 30 · WEEK 4
Mock Interview Day
Goal of the day
- Practice under real time pressure — 4 problems, each with a countdown timer, simulating the clock of an actual interview instead of the untimed comfort of a normal practice session.
- Rehearse the discipline from Day 28: state the brute force and its complexity out loud first, name the pattern you're reaching for and why, then write code.
- Compare your attempt against a full solution and walkthrough for each problem, honestly — the timer is a practice tool, not a pass/fail gate.
Concept
Every pattern in this course has been taught untimed, one at a time, with the day's title already telling you the answer. A real interview gives you none of that — a problem, a blank editor, and a clock that's usually somewhere between 20 and 45 minutes for a single question, onsite rounds sometimes tighter. The skill this builds isn't new algorithm knowledge; it's calibrating how much time each phase of solving actually takes when someone is watching and the clock is real.
Use each timer exactly like a real interview: press Start, then say your plan out loud (even alone, actually say it) before typing anything. If the buzzer hits zero before you're done, that's useful data, not a failure — note which phase ate the time (usually either clarifying too long, or debugging code that skipped the "trace it by hand first" step) and keep going anyway. The full solution and walkthrough are available any time via the reveal buttons, timer running or not.
Diagram: how to spend a 25-minute clock
4 timed mock-interview problems
Press Start, then work the problem for real before revealing anything. All 4 are Medium — the typical difficulty of a real onsite round.
1. Longest Palindromic Substring (Medium — LeetCode: Longest Palindromic Substring)
Given a string, return its longest palindromic substring. Suggested time: 20 minutes.
Press Start when you begin working the problem.
function longestPalindrome(s) {
if (s.length < 2) return s;
let start = 0, maxLen = 1;
function expand(l, r) {
while (l >= 0 && r < s.length && s[l] === s[r]) { l--; r++; }
return [l + 1, r - 1]; // the last valid palindrome bounds
}
for (let i = 0; i < s.length; i++) {
const [l1, r1] = expand(i, i); // odd-length center at i
if (r1 - l1 + 1 > maxLen) { start = l1; maxLen = r1 - l1 + 1; }
const [l2, r2] = expand(i, i + 1); // even-length center between i and i+1
if (r2 - l2 + 1 > maxLen) { start = l2; maxLen = r2 - l2 + 1; }
}
return s.substring(start, start + maxLen);
}
Walkthrough: every index is
tried as both an odd-length center (single character) and an even-length center (gap between
two characters) — that covers every possible palindrome shape. expand grows
outward while the characters on both sides keep matching, and returns the bounds of the last
valid match. Whichever expansion produces a longer palindrome than anything seen so far
updates start/maxLen. Time O(n²) (n centers, up to O(n) expansion
each), space O(1) beyond the output.
2. Merge Intervals (Medium — LeetCode: Merge Intervals)
Given a list of intervals, merge all overlapping intervals and return the merged list. Suggested time: 20 minutes.
Press Start when you begin working the problem.
function mergeIntervals(intervals) {
if (intervals.length === 0) return [];
const sorted = intervals.slice().sort((a, b) => a[0] - b[0]);
const result = [sorted[0].slice()];
for (let i = 1; i < sorted.length; i++) {
const last = result[result.length - 1];
const [start, end] = sorted[i];
if (start <= last[1]) {
last[1] = Math.max(last[1], end); // overlaps — extend the last merged interval
} else {
result.push([start, end]); // no overlap — starts a new merged interval
}
}
return result;
}
Walkthrough: sorting by
start time means every interval that could possibly overlap the one currently being built is
guaranteed to be checked before we move past it. start <= last[1] is the
overlap test — note it's <=, not <, since touching intervals
like [1,4] and [4,5] should still merge into [1,5].
Time O(n log n), dominated by the sort; space O(n) for the output.
3. Rotting Oranges (Medium — LeetCode: Rotting Oranges)
Given a grid where each cell is empty (0), a fresh orange (1), or a rotten orange (2), and every minute a rotten orange rots its fresh orange neighbors, return the minimum minutes until no fresh orange remains, or -1 if that's impossible. Suggested time: 20 minutes.
Press Start when you begin working the problem.
function orangesRotting(grid) {
const rows = grid.length, cols = grid[0].length;
const queue = [];
let fresh = 0;
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
if (grid[r][c] === 2) queue.push([r, c, 0]); // seed with EVERY already-rotten cell
else if (grid[r][c] === 1) fresh++;
}
}
const dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]];
let minutes = 0;
let qi = 0;
while (qi < queue.length) {
const [r, c, t] = queue[qi++];
minutes = Math.max(minutes, t);
for (const [dr, dc] of dirs) {
const nr = r + dr, nc = c + dc;
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && grid[nr][nc] === 1) {
grid[nr][nc] = 2;
fresh--;
queue.push([nr, nc, t + 1]);
}
}
}
return fresh === 0 ? minutes : -1;
}
Walkthrough: seeding the
queue with every rotten cell at once (not just one) is what makes this multi-source BFS — the
same trick Day 24's 01 Matrix used for "distance to nearest 0-cell." Every cell's t
is exactly how many minutes it took to rot, so the answer is the largest t
reached. Any fresh orange never visited means it was unreachable — the fresh
counter catches that and returns -1 instead of a wrong number. Time O(rows × cols),
space O(rows × cols) for the queue in the worst case.
4. Longest Common Subsequence (Medium — LeetCode: Longest Common Subsequence)
Given two strings, return the length of their longest common subsequence (not necessarily contiguous in either string, but in the same relative order in both). Suggested time: 25 minutes — the first 2D DP table in the course, budget extra time to set up the grid correctly.
Press Start when you begin working the problem.
dp[i][j] is
the LCS length using the first i characters of text1 and the first j
characters of text2. If those two characters match, extend the diagonal
(dp[i-1][j-1] + 1); if they don't, take the best of dropping one character from
either string (max(dp[i-1][j], dp[i][j-1])).function longestCommonSubsequence(text1, text2) {
const m = text1.length, n = text2.length;
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
if (text1[i - 1] === text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1; // characters match — extend the diagonal
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); // no match — best of dropping either side
}
}
}
return dp[m][n];
}
Walkthrough: row 0 and
column 0 are implicit base cases — an empty string has an LCS of length 0 with anything, which
is exactly what .fill(0) already gives every cell before the loop runs.
dp[i][j] only ever depends on the cell diagonally above-left, directly above, or
directly left — every one of those is guaranteed already filled by the time row-major order
reaches (i, j). This is the same "cache overlapping subproblems" idea as Days
25-26, just stretched across 2 dimensions instead of 1. Time O(m × n), space O(m ×
n) for the table.
Complexity — all 4 problems
| Problem | Time | Space | Pattern |
|---|---|---|---|
| Longest Palindromic Substring | O(n²) | O(1) | Expand around center (two-pointer variant) |
| Merge Intervals | O(n log n) | O(n) | Sort + one linear pass |
| Rotting Oranges | O(rows × cols) | O(rows × cols) | Multi-source BFS |
| Longest Common Subsequence | O(m × n) | O(m × n) | 2D Dynamic Programming |
Interview corner
- What do you do if you finish with time still on the clock? Don't stop — trace your code against the given example out loud, then think of an edge case the example doesn't cover (empty input, all-identical elements, a single element) and trace that too. Finishing early and using the remaining time to verify is a stronger signal than finishing early and going quiet.
- What do you do if the timer runs out before you're done? Keep going — say so
out loud ("I'm past my time budget, let me finish this last piece"), and finish the thought.
Afterward, honestly identify which phase ate the extra time (usually clarifying too long, or
debugging code that was never hand-traced first) so the next mock session budgets it better.
⚠ Trap: panicking and abandoning a mostly-correct approach to try something completely different with 5 minutes left is almost always worse than finishing the original plan a few minutes late. - What should "talking while coding" actually sound like? Short, present-tense narration of what you're about to type and why — "I'm sorting by end time here because that's what makes the greedy choice safe" — not a monologue explaining the whole algorithm before you've written a line, and not silence. Interviewers are listening for your reasoning to stay visible the entire time, not just at the start.
- Why do multiple timed mock sessions matter more than one long untimed one?
Time pressure calibration is a skill with its own learning curve, separate from knowing the
algorithms — the first few timed attempts are almost always slower than expected, purely from
the unfamiliar pressure of narrating out loud while a clock runs. That gap closes with
repetition, the same way any timed skill improves with practice under the actual constraint, not
practice without it.
↳ Common follow-up: "How many mock sessions before it stops feeling this awkward?" — there's no universal number, but most people notice a real difference by their 4th or 5th timed attempt. Re-run today's 4 problems again in a few days once the solutions have faded from memory.
Quiz
1. What's the recommended first move when a timer starts on a new problem?
2. Why state a brute-force approach out loud even if you're not going to code it?
3. If the countdown timer hits zero and you're not done, what should you do?
4. If you finish a problem with time remaining, what's the best use of the rest of the clock?
5. Why does repeating timed mock interviews matter more than one long untimed practice session?