Fundamental Problems Tutorials
Coding interview problems worked end to end — the brute force, why it is not enough, the idea that fixes it, and clean Java and Python solutions with the edge cases that actually get you rejected.
- LeetCode 543 – Diameter of Binary TreeTagged Easy, and the pattern carries most of the Hard tree problems: the recursion returns one quantity to its caller while updating a different one globally. Depth goes up, diameter gets recorded. Why left + right is already in edges despite counting nodes, and why nonlocal in Python is the difference between working and silently returning zero.
- LeetCode 347 – Top K Frequent ElementsThe statement contains its own hint: better than O(n log n). That sentence exists to rule out sorting and a max-heap of everything — and the defence that there are usually few unique values is not a complexity argument. A min-heap capped at k works; bucket sort gets it to O(n), because frequencies are small bounded integers you can index by.
- LeetCode 200 – Number of IslandsThe most common graph question in interviews, and it does not look like one — recognising that a grid is a graph is most of what is being tested. Count starts and erase the island so it cannot be counted twice. Why you must mark visited before recursing, the input-mutation trade to say out loud, and when the recursion depth forces BFS.
- LeetCode 121 – Best Time to Buy and Sell StockWorth more than its Easy tag, because the reframing it teaches is the one behind Kadane's algorithm and most 1-D DP. The brute force asks which pair of days is best; the linear solution asks what the best buy was if I sell today — and that has a one-variable answer. Why a falling market returns 0, and why this is Maximum Subarray in disguise.
- LeetCode 49 – Group AnagramsA hashing problem wearing a string problem's clothes. Find something identical for anagrams and different for everything else, then group by it. Sorting each word works; counting letters is better. And the separator everyone forgets — without it a word with 1 a and 11 b's collides with one that has 11 a's and 1 b.
- LeetCode 47 – Permutations IIPermutations with duplicates, and the extra line is a different extra line from the one Combination Sum II uses — which catches people who think they already learned this trick. With no start index, used[] is the only signal of depth, so the rule becomes !used[i-1]. All three de-duplication rules compared side by side.
- LeetCode 46 – PermutationsThe reference implementation of backtracking, and its value is the contrast with the combination problems. There a start index stops the same set appearing in different orders; here the different orders are the answer, so start disappears and used[] takes its job. Undo both pieces of state, or you get one permutation and then nothing.
- LeetCode 43 – Multiply StringsLong multiplication as you learned it at school and then forgot. It hinges on one piece of index arithmetic — the product of digits i and j lands at i + j + 1, carrying into i + j — which is worth deriving rather than memorising. Why the result needs exactly m + n slots, and why an intermediate slot going above 9 is harmless.
- LeetCode 42 – Trapping Rain WaterOne of the most-asked Hard problems, and it defeats people because they try to find the puddles. Do not. Ask how deep the water is above one column and the answer is one line: min(maxLeft, maxRight) − height. Why two pointers can decide with half the information, and the line ordering that silently returns a number slightly too small.
- LeetCode 41 – First Missing PositiveHard because of its constraints, not its question — a hash set solves it instantly, and O(1) space forbids one. Everything follows from a single observation: with n elements the answer is always in [1, n + 1], so every other value is noise. Cyclic sort uses the array as its own hash table, and the nested loop really is O(n).
- LeetCode 40 – Combination Sum IICombination Sum with two changes: each element used once, and the input may contain duplicates. The first is one character; the second is one line — and `i > start` rather than `i > 0` is the most misunderstood condition in the backtracking family. Getting it wrong does not duplicate answers, it loses them, which is far harder to notice.
- LeetCode 39 – Combination SumThe backtracking template with one twist: candidates may be reused without limit, which changes exactly one character in the recursive call. Why recursing from i rather than i + 1 is the whole difference, how the start index makes results unique structurally instead of by filtering, and why all-positive candidates are what guarantee the recursion terminates.
- LeetCode 36 – Valid SudokuNo algorithm at all — a bookkeeping problem. Rows, columns and all nine boxes can be checked in a single pass, and the only interesting line is the formula mapping a cell to its box: (row / 3) * 3 + col / 3. Encoding three facts per cell into one set, why valid is not the same as solvable, and the bitmask version for when you are asked to drop the hashing.
- LeetCode 34 – Find First and Last Position of Element in Sorted ArrayPlain binary search finds an occurrence; this wants the first and the last, and expanding outwards from a hit is O(n) the moment the array is all one value. The clean answer is one primitive — lower bound — called twice, with target + 1 giving the second answer. Why the window is half-open, and why removing the equality test removes the bugs.
- LeetCode 33 – Search in Rotated Sorted ArrayA rotated array is not sorted, so binary search should not work on it. It does, because however you cut it in half at least one half is properly sorted — and telling which is a single comparison. Why that comparison needs <= and not <, the overflow-safe midpoint, and why the duplicates variant provably degrades to O(n).
- LeetCode 31 – Next PermutationA problem you either see or you do not — no data structure, no recursion, just three passes in the right order. It starts from one observation: a descending suffix is already maximal, so the change has to reach further left than it goes. Finding the pivot, why scanning from the right finds the smallest larger value for free, and why reversing beats sorting the suffix.
- LeetCode 28 – Implement strStr()Reimplement indexOf. The honest answer to 'do I need to write KMP?' is almost always no — the interviewer wants a clean nested loop with correct bounds, and the bounds are the entire problem. Why i <= n - m is not a typo, how it handles a too-long needle for free, why not to allocate a substring per position, and how to raise KMP without walking into it.
- LeetCode 23 – Merge k Sorted ListsMerging two lists is solved; the question is in what order you merge k of them, and the obvious order costs a factor of k. Where that extra factor comes from, why pairwise merging gets it to O(N log k), and an honest comparison of divide-and-conquer against a min-heap — same time, different space, and only one of them survives the streaming follow-up.
- LeetCode 22 – Generate ParenthesesThe problem that teaches constrained backtracking. The lazy solution builds all 4^n bracket strings and filters; the intended one never builds an invalid string, because two small rules make it impossible. Why close < open is sufficient — not just true — the undo step everyone forgets, and why the output being Catalan-sized bounds any possible solution.
- LeetCode 21 – Merge Two Sorted ListsThe merge step of merge sort, isolated. Worth writing carefully rather than quickly, because Merge k Sorted Lists calls it and so does sorting a linked list. The part people over-engineer: splice the remaining list on in a single assignment instead of looping it out. Why the space is O(1), and why <= rather than < is the detail that shows you were thinking.
- LeetCode 20 – Valid ParenthesesThe canonical 'you should have reached for a stack' problem. Nesting means the thing you must close next is the thing you opened most recently. The trick that shortens the code: push the closer you expect, not the opener, so the check becomes one equality test. Three failure modes, three checks — and why ArrayDeque beats the legacy Stack.
- LeetCode 19 – Remove Nth Node From End of ListYou cannot walk a singly linked list backwards, so the nth node from the end has to be found from the front. Two pointers held a fixed distance apart do it in one pass — but the gap is n + 1, not n, because unlinking a node needs the node before it. Why the dummy head is not optional here, and an honest note on what 'one pass' actually buys.
- LeetCode 15 – 3SumThe problem that teaches sort-then-two-pointers. The algorithm is the easy half; the half that decides whether you pass is de-duplication, and there are two separate places a duplicate gets in. Why sorting buys three things at once, why the anchor skip must compare backwards, and why no solution can beat O(n²) when the output itself can hold that many triplets.
- LeetCode 14 – Longest Common PrefixA five-minute problem whose only real content is the edge cases. Scanning vertically — one character position down the whole array before moving right — is shorter than the horizontal version, exits at the first mismatched column, and makes the bounds check handle both short strings and empty ones in a single line. Plus the sorting trick, and why it is the worse answer.
- LeetCode 13 – Roman to IntegerThe inverse of Integer to Roman, and the trick that solved that one does not transfer. Going this way, all six subtractive pairs are handled by a single comparison: if a symbol is smaller than the one after it, subtract it. No table of pairs, no lookahead bookkeeping, and you never need to recognise CM as a unit. Java and Python, plus why not to rebuild a HashMap on every call.
- LeetCode 12 – Integer to RomanIt looks like it needs a pile of special cases — four is IV, nine is IX, forty is XL. It does not. Put the six subtractive pairs into the symbol table as if they were symbols in their own right, and the problem collapses into a plain greedy loop with no branches at all. Why greedy is provably safe once the table is descending, and why String += is the wrong way to build the answer.
- LeetCode 10 – Regular Expression MatchingThe first genuinely Hard problem on the list, and the difficulty is not the code. '*' is not a character — it is a modifier on the character to its left, so x* is one indivisible unit with two branches you must both try. The recursion, why it is exponential, the memo that needs Boolean rather than boolean, the bottom-up table, and the first row that is not all false.
- LeetCode 9 – Palindrome NumberTrivial with toString, which is why the follow-up — solve it without converting to a string — is the real question. Reversing only half the number cannot overflow, unlike reversing all of it. The loop that stops at the midpoint, the odd-digit case that needs reversed / 10, and the trailing-zero guard that makes 10 return false instead of true.
- LeetCode 8 – String to Integer (atoi)Almost no algorithm — a specification-reading exercise dressed as a coding problem, asked because sloppy engineers write parsers that eat production data. The rule that catches people is that atoi clamps to INT_MIN/INT_MAX where Reverse Integer returns zero. Four ordered steps, overflow detected before it happens, and the two Python traps: str.isdigit() and unbounded integers.
- LeetCode 7 – Reverse IntegerTagged Easy, and it is not quite. Reversing the digits takes four lines; the problem is detecting 32-bit overflow without being allowed a 64-bit type. Two ways to check — undo the step, or rearrange the inequality — plus why Java's truncating % carries the sign for free, why Math.abs breaks on Integer.MIN_VALUE, and why Python needs the opposite care because its integers never overflow.
- LeetCode 5 – Longest Palindromic SubstringCounting substrings is O(n³) and the DP table costs O(n²) memory. Neither is the answer you want: a string has only 2n − 1 centres, and expanding around each one is O(n²) time in O(1) space and about fifteen lines. The even-length centre everyone forgets, the hi − lo − 1 off-by-one, the interval DP for when you need it, and where Manacher's linear algorithm fits.
- LeetCode 2 – Add Two NumbersLong addition wearing a linked list costume. Reverse digit order is a gift, not an obstacle — it points the lists the same way the carry travels. The dummy head that removes the first-node special case, the carry in the loop condition that gives 999 + 1 its fourth node, and why converting to an integer overflows on the real test cases. Java and Python, plus the forward-order follow-up.
- LeetCode 1 – Two SumThe first problem on LeetCode, and still the most common phone-screen warm-up. It is not a test of whether you can find two numbers — it is a test of whether you reach for a hash map the moment you catch yourself writing a nested loop. One pass, look up before you insert, and the target = 2 × nums[i] case that lets an element pair with itself. Java and Python, plus the sorted two-pointer variant that 3Sum is built on.
- Max Subset Sum No AdjacentWrite a function that takes in an array of positive integers and returns the maximum sum of non-adjacent elements in the array. If the input array is empty, the function should return 0. Sample input [75, 105, 120, 75, 90, 135] Sample output 330 = 75 + 120 + 135 Solution Time Complexity: O(n) Space…
- Minimal Waiting TimeYou’re given a non-empty array of positive integers representing the amounts of time that specific queries take to execute. Only one query can be executed at a time, but the queries can be executed in any order. A query’s waiting time is defined as the amount of time that it must wait before its…
- Nth FibonacciThe Fibonacci sequence is defined as follows: the first number of the sequence is 0, the second number is 1, and the nth number is the sum of the (n – 1)th and (n – 2)th numbers. Write a function that takes in an integer n and returns the nth Fibonacci number. I have a […]
- Palindrome CheckWrite a function that takes in a non-empty string and that returns a boolean representing whether the string is a palindrome. A palindrome is defined as a string that’s written the same forward and backward. Note that single-character strings are palindromes. Solution Loop through half of the…
- Binary SearchWrite a function that takes in a sorted array of integers as well as a target integer. The function should use the Binary Search algorithm to determine if the target integer is contained in the array and should return its index if it is, otherwise -1. I have a solution here.
- Quick SortWrite a function that takes in an array of integers and returns a sorted version of that array. Use the Quick Sort algorithm to sort the array. I have a solution here.
- Three Number SumWhere the two-pointer technique stops being a curiosity and becomes the tool — sorting buys three separate things at once and no hash-based approach gets all three. Why both pointers move after a hit, why the result should be List<List<Integer>> rather than List<Integer[]>, and exactly what changes when duplicates are allowed.
- Two Number SumThree reasonable answers with genuinely different trade-offs, and laying all three out before choosing is the actual skill being tested. Why the inner loop starts at x + 1 rather than 0, why you must check the set before inserting or an element pairs with itself, and why sorting quietly reorders the caller's array. Java and Python, plus the indices variant.
- Fizzbuzz
- Recursion in Coding InterviewsMost people can explain what recursion is and still freeze when a problem needs it under time pressure. The three questions that turn a blank page into a fill-in-the-blanks exercise, the leap of faith that stops you tracing calls in your head, when recursion is the wrong tool, and how to reason about the cost of a branching search.
- Class PhotosIt’s photo day at the local school, and you’re the photographer assigned to take class photos. The class that you’ll be photographing has an even number of students, and all these students are wearing red or blue shirts. In fact, exactly half of the class is wearing red shirts, and the other half…