Design a parking lot (LLD / machine coding)
Expected question
"Design a multi-level parking lot that assigns spots by vehicle type, issues tickets on entry, and computes fees on exit. Support concurrent entry/exit safely."
Variant forms
Interviewers often ask the same structure with different framing or Staff+ extensions — recognize the archetype:
- "Design a parking lot LLD — spots, tickets, fees."
- "How do you assign the nearest available spot of the right size?"
- "Motorcycle can take car spot? Model vehicle hierarchy."
- "Compute fees with free first hour and progressive rates."
- "Make entry/exit thread-safe under concurrent gates."
- "Add reservations and expiring holds."
- "How do you avoid double-assigning the same spot?"
- "Extend to EV chargers with occupancy + power constraints."
The question, as it might actually be asked
Design a multi-level parking lot that assigns spots by vehicle type, issues tickets on entry, and computes fees on exit. Support concurrent entry/exit safely.
The framework
Clarify constraints → entities → allocation strategy → fee policy → thread-safety.
Where this actually gets asked
Among the highest-frequency LLD problems (parking lot appears in a large fraction of machine-coding rounds). Tests OOP, Strategy, and concurrency.
Problem
Implement park/leave with:
- Spot types: motorcycle, compact, large
- Vehicle types mapping to allowable spots
- Ticket with entry timestamp
- Fee strategy (hourly flat for interview)
Clarifying questions you should ask first
- Levels and spot counts per type?
- Can a car take a large spot? (usually yes)
- Fee model?
- Concurrent gates?
- Reservation / EV — out of scope?
Approach ladder
| Step | Idea |
|---|---|
| Brute | One list of free spots |
| Correct | Typed free-sets + ticket map |
| Staff+ | Strategy for allocation + priced fees + locks |
Reference solution (Python)
from __future__ import annotations
from dataclasses import dataclass
from enum import Enum
from threading import Lock
import time
import uuid
class SpotType(Enum):
MOTORCYCLE = 1
COMPACT = 2
LARGE = 3
class VehicleType(Enum):
MOTORCYCLE = 1
CAR = 2
BUS = 3
# vehicle can use spot if spot.value >= vehicle.value (bus needs LARGE only)
ALLOW = {
VehicleType.MOTORCYCLE: {SpotType.MOTORCYCLE, SpotType.COMPACT, SpotType.LARGE},
VehicleType.CAR: {SpotType.COMPACT, SpotType.LARGE},
VehicleType.BUS: {SpotType.LARGE},
}
@dataclass
class Spot:
id: str
level: int
type: SpotType
@dataclass
class Ticket:
id: str
spot_id: str
vehicle_type: VehicleType
entry_ts: float
class ParkingLot:
def __init__(self, spots: list[Spot], hourly_rate: float = 10.0) -> None:
self.hourly_rate = hourly_rate
self._lock = Lock()
self._free: dict[SpotType, list[Spot]] = {t: [] for t in SpotType}
self._all = {s.id: s for s in spots}
for s in spots:
self._free[s.type].append(s)
self._active: dict[str, Ticket] = {}
def _allocate(self, vt: VehicleType) -> Spot | None:
for st in (SpotType.MOTORCYCLE, SpotType.COMPACT, SpotType.LARGE):
if st in ALLOW[vt] and self._free[st]:
return self._free[st].pop()
return None
def park(self, vehicle_type: VehicleType) -> Ticket:
with self._lock:
spot = self._allocate(vehicle_type)
if spot is None:
raise RuntimeError("lot full for vehicle type")
t = Ticket(id=str(uuid.uuid4()), spot_id=spot.id,
vehicle_type=vehicle_type, entry_ts=time.time())
self._active[t.id] = t
return t
def leave(self, ticket_id: str, now: float | None = None) -> float:
with self._lock:
t = self._active.pop(ticket_id, None)
if t is None:
raise KeyError("unknown ticket")
spot = self._all[t.spot_id]
self._free[spot.type].append(spot)
now = time.time() if now is None else now
hours = max(1.0, (now - t.entry_ts) / 3600.0) # ceil-ish min 1h
return round(hours * self.hourly_rate, 2)
Complexity: park/leave O(1) amortized with typed free lists.
Verbal tests to narrate
- Car parks in compact; leave returns fee ≥ hourly_rate
- Bus only takes large; lot with only compact → full error
- Two threads parking last spot — one wins (lock)
Staff+ deep dive
| Topic | Talking point |
|---|---|
| Allocation strategy | Nearest-to-entrance vs first-fit — Strategy pattern |
| Concurrency | Single lock vs per-level locks |
| Pricing | Progressive rates, lost ticket |
| Extensibility | EV spots without rewriting core |
What not to discuss
- Payment gateway integrations in a 45-minute LLD
- Computer vision license-plate ML
What's expected at each level
- Mid-level: classes for spot/car/ticket.
- Senior: typed allocation + fees + clear API.
- Staff+: concurrency + strategy for allocation/pricing.
- Principal: multi-lot campus routing and utilization analytics hook points.
Follow-up questions to expect
- "How do you prefer closer spots?" — priority queues per type keyed by distance.