Knowledge Guide
HomeHands-On BuildsLLD Katas

Build a Parking Lot

Build a Parking Lot

The parking lot is the canonical LLD interview opener — and most candidates stall the moment "model it" turns into "make two cars not grab the same spot under load." You already understand the class breakdown from the Design a Parking Lot walkthrough; this project makes you build it from an empty file in Go and Java, with O(1) allocation and a concurrency test that fails loudly when you forget the lock. That gap — from "I can draw the classes" to "I shipped the allocator and debugged its race" — is what the interviewer is actually probing.

The spec

Build a lot with this contract, then grow it in milestones:

Milestones

Reference implementation — the allocator (Go)

The whole trick is the per-size free-list: allocation and release are O(1) stack ops, never a scan. One mutex makes the pop/push atomic so two goroutines can't pop the same spot.

type SpotType int
const (Motorcycle SpotType = iota; Compact; Large)

type Lot struct {
    mu   sync.Mutex
    free map[SpotType][]int   // size → stack of free spot IDs
}

// smallest-fit order, then upgrade to a larger free size.
var fitOrder = map[SpotType][]SpotType{
    Motorcycle: {Motorcycle, Compact, Large},
    Compact:    {Compact, Large},
    Large:      {Large},
}

func (l *Lot) Park(v SpotType) (spot int, ok bool) {
    l.mu.Lock(); defer l.mu.Unlock()
    for _, s := range fitOrder[v] {
        if n := len(l.free[s]); n > 0 {
            spot = l.free[s][n-1]
            l.free[s] = l.free[s][:n-1]   // pop — O(1)
            return spot, true
        }
    }
    return 0, false                        // full for this vehicle
}

func (l *Lot) Unpark(spot int, s SpotType) {
    l.mu.Lock(); defer l.mu.Unlock()
    l.free[s] = append(l.free[s], spot)    // push — O(1)
}

Reference implementation — the allocator (Java)

enum SpotType { MOTORCYCLE, COMPACT, LARGE }

final class Lot {
    private final Map<SpotType, Deque<Integer>> free = new EnumMap<>(SpotType.class);
    private static final Map<SpotType, List<SpotType>> FIT = Map.of(
        SpotType.MOTORCYCLE, List.of(SpotType.MOTORCYCLE, SpotType.COMPACT, SpotType.LARGE),
        SpotType.COMPACT,    List.of(SpotType.COMPACT, SpotType.LARGE),
        SpotType.LARGE,      List.of(SpotType.LARGE));

    synchronized Integer park(SpotType v) {          // null when full
        for (SpotType s : FIT.get(v)) {
            Deque<Integer> d = free.get(s);
            if (d != null && !d.isEmpty()) return d.pop();   // O(1)
        }
        return null;
    }
    synchronized void unpark(int spot, SpotType s) {
        free.get(s).push(spot);                       // O(1)
    }
}

Note the deliberate order in park: hold ONE lock across "find a free spot AND remove it." Splitting find from remove is the classic bug — see the test below.

Tests to write (this is the real learning)

Real-world scenarios — EV charging & dynamic pricing (the common follow-up)

The most-asked "make it real" escalation adds two things a modern lot has: EV charging spots and peak/occupancy pricing. Interview caution (worth saying out loud): don't volunteer a complex pricing engine unless asked — propose it as an extension, then build it if they bite. The key design move is that pricing is a strategy, not an if-else in the exit gate: the allocator never changes.

// Go — pricing is a strategy; the allocator never sees it.
type FareStrategy interface { Fee(d time.Duration, t SpotType, occupancy float64) float64 }

type SurgeFare struct{ base, ratePerHr float64 }
func (s SurgeFare) Fee(d time.Duration, t SpotType, occ float64) float64 {
    mult := 1.0
    if occ > 0.9 { mult = 2.0 } else if occ > 0.75 { mult = 1.5 } // occupancy surge
    return (s.base + s.ratePerHr*d.Hours()) * mult
}
// Java — same shape; inject the strategy, swap at runtime.
interface FareStrategy { double fee(Duration d, SpotType t, double occupancy); }

final class SurgeFare implements FareStrategy {
    private final double base, ratePerHr;
    SurgeFare(double base, double ratePerHr){ this.base=base; this.ratePerHr=ratePerHr; }
    public double fee(Duration d, SpotType t, double occ) {
        double mult = occ > 0.9 ? 2.0 : occ > 0.75 ? 1.5 : 1.0;   // occupancy surge
        return (base + ratePerHr * d.toMinutes()/60.0) * mult;
    }
}

Test it: at occupancy 0.95 the fee is 2× the base rate; drop below 0.75 and it returns to 1×. And confirm the idle fee kicks in only after a charging session reports full — a car still charging pays the parking rate, not the idle penalty.

Extensions — take it further

What you've mastered when this is done


Re-authored/Deepened for this guide. Model answer: the Design a Parking Lot LLD walkthrough.

🤖 Don't fully get this? Learn it with Claude

Stuck on Build a Parking Lot? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Build a Parking Lot** (Hands-On Builds) and want to truly understand it. Explain Build a Parking Lot from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Build a Parking Lot** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Build a Parking Lot** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Build a Parking Lot** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes