Coding by Hand
Rust home

LeetCode Warm-Ups

A LeetCode problem is a single warm-up drill at the gym. The drill is short, the rules are tight, the bar is set, and you are training one specific muscle — not your whole body. A programmer who solves a hundred of these has trained one specific muscle a hundred times: pattern recognition under a clock, where you see a small puzzle and your hand reaches for the right shape of solution before your brain finishes reading the prompt. That muscle matters in a 45-minute hiring interview and almost nowhere else. Real systems work is mostly about reading other people's code, naming things, deciding which trade-off you can live with, and waiting for a flaky network to come back. Treat these problems like the warm-up rack: useful before the real lift, never a substitute for it.

A gym warm-up rack with the empty bar and a clock above it, the way LeetCode drills feel before a real session.
A gym warm-up rack with the empty bar and a clock above it, the way LeetCode drills feel before a real session.

The name LeetCode comes from a website a small team launched in 2015 in Mountain View, California, to scrape and host the kind of puzzles big tech companies were already using in interviews. The puzzles themselves are older. Programming contests at universities had been collecting them since the 1970s, the ACM International Collegiate Programming Contest started ranking them in 1977, and Google's first phone screens in the early 2000s pulled from the same well. The shift LeetCode made was packaging — a stopwatch in the corner, a difficulty tag, a discussion tab, a leaderboard. That packaging is also why the site gets criticized. It rewards a narrow skill on a narrow stage, and a lot of working engineers spend a lot of evenings drilling it not because their day job needs it but because the next job's interview probably will. Useful warm-up, not the whole gym.

Two classics. Two Sum is the first drill on the rack. Given a list of numbers and a target, find the two numbers that add to the target and return where they sit in the list. The shape of the answer is obvious — check every pair, two nested loops, done. That works for a list of ten. It does not work for a list of a million, because checking every pair of a million is a trillion checks. The drill trains the muscle that says wait, I can do this in one pass if I remember what I have already seen. The thing that remembers is a hash map. Walk the list once. At each number, ask the map whether the partner I would need to hit the target has already shown up. If yes, return both spots. If no, write down the current number with its index and keep walking.

Walking the input once and asking a hash map whether the partner for each number was already seen.
Walking the input once and asking a hash map whether the partner for each number was already seen.
fn two_sum(nums: &[i32], target: i32) -> Option<(usize, usize)> {
    let mut seen: HashMap<i32, usize> = HashMap::new();
    for (i, &n) in nums.iter().enumerate() {
        let need = target - n;
        if let Some(&j) = seen.get(&need) {
            return Some((j, i));
        }
        seen.insert(n, i);
    }
    None
}

Read it once. The map is keyed by number and stores the index where that number was seen. The loop walks the slice with enumerate so each step has both the index and the value. The line let need = target - n is the question — what partner would I need? The seen.get(&need) is the lookup. A hit returns the pair of indices with the older one first. A miss writes the current number into the map and the loop moves on. If the loop walks off the end, the function returns None. The whole pass is one walk. The map lookup and insert are average constant time, so the work scales straight with the length of the list — what computer scientists write as O(n) and what the gym would call clean form on a heavy set.

fn run_two_sum() {
    println!("-- two sum (LeetCode #1) --");
    println!("problem: given a list of numbers and a target,");
    println!("         return the two indices whose values add to the target.");
    let nums: [i32; 6] = [2, 7, 11, 15, 3, 6];
    let target: i32 = 9;
    println!("input nums   = {nums:?}");
    println!("input target = {target}");
    match two_sum(&nums, target) {
        Some((a, b)) => println!("output pair  = ({a}, {b})  -> {} + {} = {target}", nums[a], nums[b]),
        None => println!("output pair  = none"),
    }
}

The driver fixes the input so the output is the same every time the page is built — six numbers and a target of 9. The pair the function finds is (0, 1) because nums[0] is 2 and nums[1] is 7 and 2 plus 7 is 9. Other valid pairs exist inside this list (3 at index 4 plus 6 at index 5) but the one-pass algorithm returns the first pair it can prove, which is whichever partner shows up second in the walk.

The second drill is Valid Parentheses. Given a string of brackets — round, square, curly — say whether every opener has a matching closer in the right order. ()[]{} is valid. ([{}]) is valid because the curlies close before the squares which close before the rounds. (] is not valid because the round opener never sees its mate. ([)] is not valid because the round closes while the square is still open in the middle — the order is wrong. The shape of the answer is a stack — the rack of weight plates at the gym. A new plate slides on at the top. The only plate you can lift off is the one at the top. You never reach into the middle of the stack. Every opener gets pushed onto the rack. Every closer pulls the top plate off and checks that the kind it pulled is the matching shape. If the rack is empty when a closer tries to pull, the string is invalid. If the rack still has plates when the string ends, the string is invalid.

Brackets pushed onto a weight-rack stack: only the top plate can come off, and the closer must match its shape.
Brackets pushed onto a weight-rack stack: only the top plate can come off, and the closer must match its shape.
fn valid_parentheses(s: &str) -> bool {
    let mut stack: Vec<char> = Vec::new();
    for c in s.chars() {
        match c {
            '(' | '[' | '{' => stack.push(c),
            ')' => {
                if stack.pop() != Some('(') {
                    return false;
                }
            }
            ']' => {
                if stack.pop() != Some('[') {
                    return false;
                }
            }
            '}' => {
                if stack.pop() != Some('{') {
                    return false;
                }
            }
            _ => return false,
        }
    }
    stack.is_empty()
}

The Vec<char> is the rack. The match arms split the work by character. Openers get pushed onto the top. Each kind of closer pops the top plate and checks what kind it pulled. The pop() method returns Option<char>Some(c) if the rack had a plate, None if the rack was empty — and the comparison handles both cases in one expression because Some('(') == Some('(') is true, None == Some('(') is false, and any mismatched pair is false too. The function returns false the moment any check fails and stack.is_empty() at the end, which catches the case where the string ended with leftover openers still sitting on the rack.

fn run_valid_parentheses() {
    println!("-- valid parentheses (LeetCode #20) --");
    println!("problem: a string of brackets is valid when every opener");
    println!("         is closed by the matching kind in the right order.");
    let cases: [&str; 4] = ["()[]{}", "([{}])", "(]", "([)]"];
    for s in cases {
        let ok = valid_parentheses(s);
        println!("input '{s}'  -> {ok}");
    }
}

Four fixed cases cover the four ways the check can swing. Two valid strings, two invalid ones. Run the binary and watch both drills print their inputs and answers side by side.

-- two sum (LeetCode #1) --
problem: given a list of numbers and a target,
         return the two indices whose values add to the target.
input nums   = [2, 7, 11, 15, 3, 6]
input target = 9
output pair  = (0, 1)  -> 2 + 7 = 9

-- valid parentheses (LeetCode #20) --
problem: a string of brackets is valid when every opener
         is closed by the matching kind in the right order.
input '()[]{}'  -> true
input '([{}])'  -> true
input '(]'  -> false
input '([)]'  -> false

The top block is the Two Sum result. The pair (0, 1) is the answer the hash-map walk found, and the trailing arithmetic 2 + 7 = 9 is the proof. The bottom block is the four parenthesis cases. The first two return true, the third and fourth return false. Notice the third case, (] — the open round goes onto the rack, then the square closer tries to pull. The pop returns Some('('), the square closer wanted Some('['), the mismatch returns false on the spot. The fourth case, ([)], is the one most people get wrong on a whiteboard because the brackets look balanced if you just count them. The stack proves they are not: round plate goes on, square plate goes on top, round closer pulls the square — wrong shape — and the function returns false without ever reading the final closer.

Two drills, two patterns. Hash map for fast lookup. Stack for nested matching. A working engineer reaches for those two shapes hundreds of times across a career, and the warm-up gives you the reflex to spot when one fits. What these drills cannot teach is how to stand up a real system — where the input is unbounded, the partner team owns half the code, the data is partly wrong, and the bug only shows up at 3 a.m. The next set of lessons is about that — the structs and methods that let you build a system instead of solve a puzzle.