Purposefully vague. Discuss the exact requirement with your interviewer.
Some questions we can ask:
How should accessibility be taken care of? Do we need to prioritize handcap parking areas, for example?
Is this a ground parking lot, or a monitored system?
How many entrances are in the parking lot? (Do we have to deal with any issues of concurancy?)
Should there by any pricing strategies in place? Do we offer premium services (reserved parking areas) to customers?
Do we need to support different types of spots for different type of vehicles?
Assumptions:
Design a monitored system for support for 4 different type of vehicles (S,M,L,XL). The parking lot supports 150 small vehicles, 100 medium vehicles, 50 large vehicles, and 25 extra large vehicles.
A smaller vehicle can only be parked in a spot that is designated to be equal or large than itself. That is a L vehicle cannot park to M spot, but can park to an L to XL spot.
Implementation:
Build an interface and support efficient implementation for the following methods:
Spot placeVehicle(Vehicle):return a spot for a Vehicle spot.
This method must return an available spot prioritized by its type. For example, a small vehicle can only be parked in a mediumed sized parking spot iff there are no small vehicle spots available.
If there are no spots available, throw an exception.
void removeVehicle(Vehicle): remove a vehicle from the parking lot.
from enum import IntEnum
import queue, copy
class Size(IntEnum):
S = 0,
M = 1,
L = 2,
XL = 3
class Vehicle:
def __init__(self, id, size):
"""
:param id: [int]
:param size: [Size]
"""
self.drivers_lic = id
self.size = size
def __hash__(self):
return hash(self.drivers_lic)
def __eq__(self, other):
return self.drivers_lic == other.drivers_lic
def __str__(self):
return str(self.drivers_lic) + " " + str(self.size)
class Car(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.M)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class MotorCycle(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.S)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class Bus(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.XL)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class Truck(Vehicle):
def __init__(self, id):
"""
:param id: [int]
"""
super().__init__(id, Size.L)
def __hash__(self):
return super().__hash__()
def __eq__(self, other):
return super().__eq__(other)
def __str__(self):
return super().__str__()
class Spot:
def __init__(self, id, size):
"""
:param id: [int]
:param size: [Size]
"""
self.id = id
self.size = size
def __eq__(self, other):
return self.id == other.id
class ParkingLot:
def __init__(self, zipcode, size_class):
"""
:param zipcode: [int]
:param size_class: List[int]
"""
self.zipcode = zipcode
self.capacities = size_class
self.counts = [0] * 4
# main datastructure to hold are parking cars
self.Park_DB = {Size.S: {}, Size.M: {}, Size.L: {}, Size.XL: {}}
# using a priority queue will ensure that when a car gets
# removed from the lot, the next available spot will be the
# next 'closest' spot to the next user.
self.spot_ids = queue.PriorityQueue()
for id in range(sum(self.capacities)):
self.spot_ids.put(id)
def place_vehicle(self, vehicle):
"""
Identifies and stores the next available parking spot
:param vehicle: [Vehicle]
:return: [Spot]
"""
# check if vehicle already exists in the lot
if any(vehicle in self.Park_DB[size] for size in Size):
raise ValueError("Duplicate Vehicle ID identified.")
# find the first available spot starting from current size
for size in range(int(vehicle.size), len(self.counts)):
if self.counts[size] < self.capacities[size]:
# a spot was found, so add the spot to the hash table
next_spot = Spot(self.spot_ids.get(), Size(size))
self.Park_DB[Size(size)][vehicle] = next_spot
self.counts[size] += 1
return next_spot
raise OverflowError("All vehicle capacities are full.")
def remove_vehicle(self, vehicle):
"""
Removes an identified vehicle from the parking lot
:param vehicle: [vehicle]
:return: [Spot]
"""
for size in range(int(vehicle.size), len(self.counts)):
if vehicle in self.Park_DB[Size(size)]:
# the vehicle was found - copy and return its spot
spot = copy.copy(self.Park_DB[Size(size)][vehicle])
# put back the available parking id spot back into queue
self.spot_ids.put(spot.id)
# remove the vehicle from the lot
del self.Park_DB[Size(size)][vehicle]
self.counts[size] -= 1
return spot
# vehicle was not found
raise LookupError("Vehicle id was unidentified in the ParkingLot")
def __str__(self):
strings = []
for size, vehicles in self.Park_DB.items():
strings.append(str(size) + ": " + "\n")
for vehicle in vehicles:
strings.append("\t" + str(vehicle) + "\n")
return ''.join(strings)