LeetCode Problems

Interview problems, but visible.

Two Sum, sliding window, BFS on a grid - the problems that show up in every interview, with the data structure visible at every step. Pause, rewind, edit the input, and ask 'why does this work?' until you actually know.

Start here

Recommended path

New to this section? Work through these in order - each builds on the previous.

  1. 1Two Sum
  2. 2Valid Parentheses
  3. 3Reverse Linked List
  4. 4Climbing Stairs
  5. 5Binary Tree Inorder Traversal

Easy classics

6

Two Sum

Easy

The brute-force solution checks every pair in O(n²). The hash-map trick: as we scan left-to-right, for each nums[i] we look up its complement (target − nums[i]) in a map of values we've already seen. The map turns the inner loop's linear scan into an O(1) lookup, so the whole thing runs in a single O(n) pass.

hash-map lookup
O(n) · O(n)Open visualization

Valid Parentheses

Easy

Walk left-to-right with a stack. Every opener gets pushed; every closer pops and must match the top. If you ever pop the wrong opener - or pop from an empty stack - the string is invalid. After the loop, the stack must be empty for the string to be valid. The stack is the perfect data structure here because brackets nest like function calls.

stack match
O(n) · O(n)Open visualization

Best Time to Buy and Sell Stock

Easy

The brute force is to try every (buy, sell) pair - O(n²). The trick is realizing you don't need to revisit history: for each day, the best sell-today profit is today's price minus the cheapest price seen so far. So track running min and running max-profit in one pass.

track minsingle pass
O(n) · O(1)Open visualization

Climbing Stairs

Easy

To reach step n, the LAST move you made was either a 1-step (from n-1) or a 2-step (from n-2). So the number of ways to reach n is the sum of the ways to reach n-1 and n-2. That's Fibonacci. Building the dp table bottom-up - dp[0]=1, dp[1]=1, then dp[i] = dp[i-1] + dp[i-2] - gives O(n) time, O(n) space; you can compress to two variables for O(1) space.

DP base + step
O(n) · O(n) (or O(1) with two rolling variables)Open visualization

Reverse Linked List

Easy

Three pointers do the whole job: prev (everything we've reversed so far), curr (the node we're about to flip), and nxt (saved so we don't lose the rest of the list). On each iteration: save nxt, flip curr.next to point at prev, then march all three pointers one step forward. At the end, prev is the new head.

pointer reversal
O(n) · O(1)Open visualization

Merge Two Sorted Lists

Easy

Two pointers, one for each list. Each step: compare heads, take the smaller one, advance that pointer. When one list runs out, append the rest of the other. The two lists must be pre-sorted; if they aren't, you're doing merge-sort's merge step on unsorted data and you'll get garbage.

two-pointer merge
O(n + m) · O(n + m) for the outputOpen visualization

Arrays & Strings

7

Maximum Subarray (Kadane's)

Medium

At every index, you have one decision: extend the running subarray, or start fresh from here. You restart when the running sum has gone negative - a negative prefix can only hurt anything you'd add after it. This dynamic-programming insight collapses the O(n³) brute force into O(n), and it's exactly the same shape as 'best time to buy/sell stock' written with a different variable.

Kadane'srunning sum
O(n) · O(1)Open visualization

Valid Palindrome

Easy

A palindrome reads the same forwards and backwards. Walk one pointer from each end toward the middle; if every pair matches, the string is a palindrome. The wrinkle is the problem's filter - only alphanumeric characters count and case is ignored - so when either pointer lands on punctuation or whitespace, slide it past before comparing. The moment a pair fails, you can return false immediately.

two pointersskip + match
O(n) · O(1)Open visualization

Rotate Array

Medium

Three reversals = one rotation. To right-rotate an array by k, first reverse the entire array - that swings every element across the midpoint but also reverses the two halves you actually want. Reverse the first k elements to un-swap that prefix, then reverse the remaining n − k to un-swap the suffix. The two locally-reversed halves cancel the global reversal exactly where you want them to. The whole thing runs in O(n) time with no extra space, beating the naive copy-into-a-buffer approach.

reverse ×3in-place
O(n) · O(1)Open visualization

Trapping Rain Water

Hard

Water trapped over a column equals min(leftMax, rightMax) - height. The clean O(n) trick uses two pointers moving inward. Whichever side's running max is smaller is also the binding constraint for the column on that side: water at that column cannot exceed it, because the OTHER side's max is even taller. So advance the smaller side, settle that column's water as (sideMax - height), update the side's max, and keep going until the pointers meet. No stacks, no extra arrays.

two pointersrunning max
O(n) · O(1)Open visualization

3Sum

Medium

Sorting is the trick. Once nums is sorted, fix one element nums[i] and the problem becomes 'find two values to its right that sum to -nums[i]' - a two-pointer sweep from both ends. If the current trio's sum is too small, advance l (left pointer) to pick up a bigger value; too big, retreat r. When you find a hit, record it, then skip duplicate neighbors on both sides so the same triplet isn't reported twice. Skipping duplicate anchors (nums[i] == nums[i-1]) keeps the result clean too. O(n²) total, beating the brute-force O(n³).

sort + 2ptrskip dups
O(n²) · O(1) extra (excluding the output)Open visualization

Longest Palindromic Substring

Medium

Every palindrome has a center - either a single character (odd length: 'racecar') or the gap between two characters (even length: 'abba'). For each possible center, expand outwards as long as the two sides keep matching. Track the longest palindrome you see. There are 2n - 1 possible centers and each expansion is O(n) in the worst case, giving O(n²) total - faster than brute-force enumeration and simpler than DP.

expand around centerodd + even
O(n²) · O(1)Open visualization

Longest Substring Without Repeating Characters

Medium

A variable-size sliding window. The right pointer always advances; the left pointer jumps forward whenever the incoming character would create a duplicate, shrinking the window until the offender is evicted. A hash set tracks what's in the window so the duplicate-check is O(1). Each character is visited at most twice (once by right, once by left) - total O(n).

sliding windowhash-set
O(n) · O(min(n, charset))Open visualization

Trees & Grids

4

Spiral Matrix

Medium

Walk the matrix in spiral order: right across the top row, down the right column, left across the bottom, up the left side - then repeat on the contracting inner rectangle. Track four boundaries (top, bottom, left, right) and shrink the relevant one after each directional walk. The trick that catches interview candidates: after walking right and down, you must also check `top <= bottom` and `left <= right` before walking left and up - otherwise on a single-row or single-column residue you'll double-walk and duplicate elements.

four boundariesshrink + walk
O(m × n) · O(1) extra (output excluded)Open visualization

Rotate Image

Medium

A 90°-clockwise rotation is the same thing as transpose + horizontal flip. Transpose swaps element (i, j) with (j, i) - turning rows into columns. After that, reversing each row flips left↔right, which finishes the rotation. Both operations work in place, so the whole rotation runs in O(n²) time with O(1) extra space. You can also do it with four-way ring swaps; the transpose-then-flip framing is just easier to remember and easier to read.

transposerow reverse
O(n²) · O(1)Open visualization

Binary Tree Inorder Traversal

Easy

Inorder = LEFT subtree, then NODE, then RIGHT subtree. The recursive version is three lines. The iterative version with an explicit stack is more interesting: you descend left as far as you can, pushing each node, then pop, visit, and try the right subtree. The stack lets you remember where to come back to. For BSTs, inorder produces values in sorted order - that's the property tests rely on.

iterativestack-based
O(n) · O(h) for the stack, h = tree heightOpen visualization

Number of Islands

Medium

Scan the grid row-by-row. Every time you hit unvisited land, you've found a new island - bump the count, then flood-fill the connected region so you don't double-count it. The flood-fill is just DFS (or BFS) over 4-directional neighbors, marking each cell as visited when you touch it. Each cell is processed at most once, so the total work is O(rows × cols).

flood fillDFS
O(rows × cols) · O(rows × cols) for the visited gridOpen visualization

Dynamic Programming

3

House Robber

Medium

Walk a row of houses; you can't rob two adjacent ones. At each house i, the best you can do is either *rob this one* (take nums[i] + best from houses 0..i-2) or *skip it* (carry forward the best from 0..i-1). Take whichever is larger. That's the recurrence dp[i] = max(dp[i-1], dp[i-2] + nums[i]). Build the dp table left-to-right and the last cell is the answer. Pedagogically: each step you literally see one of two paths win - taking-current vs. carrying-prior.

rob vs skip1D DP
O(n) · O(n) (can compress to O(1) with two rolling variables)Open visualization

Coin Change

Medium

Build the answer bottom-up. dp[i] holds the minimum coins to reach amount i. Start with dp[0] = 0 (zero coins make zero). For every amount from 1 up to the target, try each coin c: if we can subtract c (i ≥ c), then one possible recipe is dp[i − c] + 1. Take the minimum across all coins. Any slot that never gets updated stays unreachable - return -1 at the end if dp[amount] is still ∞.

unbounded knapsackbottom-up DP
O(amount × coins) · O(amount)Open visualization

Word Break

Medium

dp[i] = true iff the first i characters of s can be carved into dictionary words. dp[0] starts true (the empty prefix is trivially segmentable). For each new length i, scan every possible last word: pick a split point j; if dp[j] is true AND s[j..i-1] is in the dictionary, then dp[i] is also true. The first witness is enough - break out of the inner loop. dp[n] is the final answer.

dp[i] = prefix segmentable?
O(n² * m) where m is the max word length · O(n + dict)Open visualization

Heaps

1

Bit Manipulation

2

Backtracking

3

Generate Parentheses

Medium

Two counters - open and close - keep the string well-formed at every step. You can ALWAYS append '(' if you haven't used all n open parens. You can append ')' only if there are unmatched opens (close < open). Recursing on those two choices builds every valid combination exactly once. The number of valid combinations is the nth Catalan number: 1, 2, 5, 14, 42 for n = 1..5.

backtrackopen / close counts
O(4^n / sqrt(n)) - Catalan number, every valid string is visited · O(n) recursion depth (excluding the output)Open visualization

Subsets

Medium

Every element is either IN the subset or OUT. Building the power set is a depth-first walk through that binary choice at each index: include nums[i] and recurse on i+1, then undo the include and recurse on i+1 again. Every leaf of that 2^n tree is one subset. Recording the running subset at the START of each call (before any choice) gives the canonical LC 78 output - the empty set first, the full set last.

include / excludepower set
O(n * 2^n) - 2^n subsets, each up to n long when copied · O(n) recursion depth (excluding the output)Open visualization

Permutations

Medium

A permutation is just a complete ordering of the input. Build one position at a time: for each unused element, place it next, recurse, then take it back out and try the next one. A boolean `used[]` (or a hash set) tells the recursion which elements are still available. When the current permutation has length n, record it and return - then unwind one level, mark the last-placed element as available again, and continue with the next candidate. n! permutations total.

used[]n! orderings
O(n! * n) · O(n)Open visualization