Parking Lot
The classic first round: floors, spot types, nearest free spot and an hourly bill in ₹.
the brief
What you are building
A mall in Pune is opening a multi-level parking. The owner wants a small program for the entry and exit gates.
Each floor has a row of spots. A spot fits one type of vehicle: a bike, a car or a truck.
At the entry gate, the system gives the vehicle the nearest free spot of its type. At the exit gate, it frees the spot and prints the bill.
No database, no UI. Just clean, working Java that the interviewer can run and read.
must have
Requirements
- Build the lot from a list of floor plans. Each plan is a string with one letter per spot:
Bbike,Ccar,Ttruck. - Spot
ion floorfhas the idf-i(for example0-3). parkgives the nearest free spot of the vehicle's type: the lowest floor first, then the lowest spot number on that floor.- A vehicle only fits its own type of spot. If none is free,
parkreturns"". - A vehicle that is already inside cannot park again:
parkreturns"". leavefrees the spot and returns the fee. Every started hour is paid in full, and the first hour is always paid.- Rates per hour: bike ₹10, car ₹20, truck ₹50.
leavefor a vehicle that is not inside returns-1. whereIsfinds a parked vehicle;freeSpotscounts the free spots of one type.
the contract
The Java API: class ParkingLot
Times are minutes from when the lot opened, passed in by the caller. This keeps the code testable: no clock inside.
public ParkingLot(String[] floors)- Floor
f's plan isfloors[f], e.g."BCC". A floor may be empty. public String park(String vehicleNo, String type, long nowMin)typeis"BIKE","CAR"or"TRUCK". Returns the spot id, or"".public int leave(String vehicleNo, long nowMin)- Frees the spot. Returns the fee in ₹, or
-1if the vehicle is not inside. public String whereIs(String vehicleNo)- The vehicle's spot id, or
""if it is not inside. public int freeSpots(String type)- How many spots of this type are free right now.
- 1 ≤ floors ≤ 50, each floor has 0 to 200 spots
- times never go backwards
- up to 10,000 calls
- vehicle numbers are non-empty strings like
KA01AB1234
example session
Calls in, answers out
Floor 0 is BCC (a bike spot, then two car spots). Floor 1 is CT.
| call | returns | why |
|---|---|---|
new ParkingLot(new String[] {"BCC", "CT"}) | — | |
park("KA01AB1234", "CAR", 0) | "0-1" | the nearest car spot |
park("MH12XY9999", "CAR", 10) | "0-2" | |
park("DL05CD0001", "CAR", 15) | "1-0" | floor 0 has no car spot left |
park("TN09EF4321", "CAR", 20) | "" | every car spot is taken |
freeSpots("CAR") | 0 | |
leave("KA01AB1234", 90) | 40 | 90 minutes = 2 started hours × ₹20 |
park("TN09EF4321", "CAR", 95) | "0-1" | the freed spot is the nearest again |
whereIs("MH12XY9999") | "0-2" | |
leave("UP16ZZ0000", 100) | -1 | this vehicle never came in |
park("KA01BK7777", "BIKE", 100) | "0-0" | |
leave("KA01BK7777", 160) | 10 | exactly 60 minutes = 1 hour × ₹10 |
freeSpots("TRUCK") | 1 |
time plan
Your 90 minutes
- 10 minclarify — Read the brief twice. Ask: can a bike use a car spot? What if the same vehicle parks twice? Write the answers down.
- 10 mindesign — List the nouns: lot, floor, spot, vehicle type, ticket, pricing. Pick one data structure per question the code must answer fast.
- 40 mincore code —
parkandleavefirst, with the fee. ThenwhereIsandfreeSpots. Run the example after each method. - 20 minedge cases — Full lot, parking twice, leaving twice, 0 minutes, exactly 60 minutes, an empty floor.
- 10 minpolish — Names, small methods, remove dead code. Be ready to explain how a new vehicle type or a new price rule fits in.
Practise under real pressure: a 90-minute clock with the phases above. It keeps running if you reload the page.
your turn
Build it here
Write the whole class in the editor. Run replays the example session; Submit adds the hidden tests (edge cases and large random sessions). Stuck for 20 minutes? Open one hint at a time.
Build ParkingLot in the browser
Design: implement every operation. Compiled by the real javac (Java 17) and judged right here — nothing is sent anywhere.
The reference, the data-structure reasoning and the rubric are hidden so you can build it first. Even a half-working attempt teaches you more than reading a perfect answer.
Opening all three hints also shows it.
reference
One clean way to build it
Records for Spot and Ticket (Java 16+), an enum for vehicle types, one heap of free spots per type, and pricing behind an interface.
class ParkingLot { /** Each type knows its letter on the floor plan and its rate. A new type is one more line. */ enum VehicleType { BIKE('B', 10), CAR('C', 20), TRUCK('T', 50); final char symbol; final int ratePerHour; // ₹ VehicleType(char symbol, int ratePerHour) { this.symbol = symbol; this.ratePerHour = ratePerHour; } } record Spot(int floor, int index) { String id() { return floor + "-" + index; } } record Ticket(Spot spot, VehicleType type, long since) {} /** Pricing is a separate rule, so a weekend or monthly-pass rule can replace it without touching parking. */ interface Pricing { int fee(VehicleType type, long minutes); } /** Every started hour is paid in full; the first hour is always paid. */ static class HourlyPricing implements Pricing { public int fee(VehicleType type, long minutes) { long hours = Math.max(1, (minutes + 59) / 60); // ceil without doubles return (int) (hours * type.ratePerHour); } } private static final Comparator<Spot> NEAREST = Comparator.comparingInt(Spot::floor).thenComparingInt(Spot::index); private final Map<VehicleType, PriorityQueue<Spot>> free = new EnumMap<>(VehicleType.class); private final Map<String, Ticket> parked = new HashMap<>(); // vehicle number → its ticket private final Pricing pricing = new HourlyPricing(); public ParkingLot(String[] floors) { for (VehicleType t : VehicleType.values()) free.put(t, new PriorityQueue<>(NEAREST)); for (int f = 0; f < floors.length; f++) { for (int i = 0; i < floors[f].length(); i++) { free.get(typeOf(floors[f].charAt(i))).add(new Spot(f, i)); } } } private static VehicleType typeOf(char symbol) { for (VehicleType t : VehicleType.values()) if (t.symbol == symbol) return t; throw new IllegalArgumentException("unknown spot type: " + symbol); } public String park(String vehicleNo, String type, long nowMin) { if (parked.containsKey(vehicleNo)) return ""; // already inside PriorityQueue<Spot> spots = free.get(VehicleType.valueOf(type)); Spot spot = spots.poll(); // the nearest free spot of this type: O(log n) if (spot == null) return ""; // full for this type parked.put(vehicleNo, new Ticket(spot, VehicleType.valueOf(type), nowMin)); return spot.id(); } public int leave(String vehicleNo, long nowMin) { Ticket t = parked.remove(vehicleNo); if (t == null) return -1; free.get(t.type()).add(t.spot()); // the spot is free again: O(log n) return pricing.fee(t.type(), nowMin - t.since()); } public String whereIs(String vehicleNo) { Ticket t = parked.get(vehicleNo); return t == null ? "" : t.spot().id(); } public int freeSpots(String type) { return free.get(VehicleType.valueOf(type)).size(); }}the choices
Which data structures, and why
enum VehicleTypeOne place for each type's letter and rate. A new type (say, an e-rickshaw) is one new line, not a new if.
O(1) lookups; the compiler catches typos that a raw string would hide.
EnumMap<VehicleType, PriorityQueue<Spot>>The free spots of each type, nearest first. The heap always knows the smallest (floor, index).
park polls in O(log n); leave adds back in O(log n). A scan of every floor would be O(n) per car.
HashMap<String, Ticket>Vehicle number → its spot, type and entry time. Answers whereIs, leave and the parked-twice check.
O(1) average per lookup.
interface PricingThe fee rule lives outside the parking logic, so a weekend rate or a monthly pass is a new class.
O(1) per bill; no change to park or leave when prices change.
self-check
Mark yourself like the interviewer would
Tick only what your code really does. Nothing is saved or sent — this is just for you.
your honest self-score: 0 / 100
traps
Common mistakes
- Scanning every floor on every
park. It works for the example, but the interviewer will ask what happens with 50 floors and a Flipkart-sale crowd. - Using
doublefor money andMath.ceil(minutes / 60):minutes / 60is integer division, so the ceil does nothing. Use(minutes + 59) / 60. - Forgetting the minimum of one hour, so a vehicle that leaves at once pays ₹0.
- Comparing vehicle types as raw strings in five places. One typo (
"Car") and a car never finds a spot. - Spending 40 minutes on a perfect class diagram and running out of time to make it work. Working code first, polish later.
what they ask next
Follow-ups and extensions
Bikes may use a car spot when the bike spots are full. How would you change it?
Give each type an ordered list of spot types it can use: a bike tries B, then C.
park polls the first heap that is not empty. The rest of the code does not change.
How would you add a weekend price, or a monthly pass?
Write a new class that implements Pricing and pass it in the constructor.
park and leave never change. This is the open/closed principle in one sentence.
Two gates call park at the same time. What breaks?
Two threads can poll at the same moment, and the HashMap can be corrupted.
The simplest fix: make park and leave synchronized. For more throughput, a lock per vehicle type, or a ConcurrentHashMap plus a PriorityBlockingQueue.
Show a display board: free spots per floor and type.
Keep a small int[floors][types] count, updated in park and leave.
That is O(1) per update and O(floors × types) to draw the board.
revise