1603. Design Parking System
Problem Description
You need to design a parking system for a parking lot that has three different sizes of parking spaces: big, medium, and small. Each size has a fixed number of available slots.
The system should support two operations:
-
Initialize the parking system with the number of slots for each size:
ParkingSystem(int big, int medium, int small)
: Creates a parking system with the specified number of big, medium, and small parking spaces.
-
Add a car to the parking lot:
addCar(int carType)
: Attempts to park a car of a given type.- Car types are represented by integers:
1
for big,2
for medium, and3
for small. - A car can only park in a space that matches its size exactly (a big car needs a big space, etc.).
- Returns
true
if there's an available space for the car type and the car is successfully parked (reducing the available count by 1). - Returns
false
if no space is available for that car type.
The solution uses an array cnt
where index 1, 2, and 3 store the available counts for big, medium, and small spaces respectively. When a car arrives, the system checks if there's space available for that car type. If yes, it decrements the count and returns true
; otherwise, it returns false
.
Intuition
The key insight is that this is a simple resource management problem. We need to track how many parking spaces of each type are available and update these counts as cars arrive.
Since we have exactly three types of parking spaces and cars can only park in their matching space type, we can think of this as having three independent counters. Each car type maps directly to its corresponding parking space type (1→big, 2→medium, 3→small).
The natural approach is to use an array to store these counts. We can leverage the fact that car types are already represented as integers (1, 2, 3), so we can use them directly as array indices. This eliminates the need for any conditional logic or mapping between car types and space types.
When a car arrives, we simply need to:
- Check if the counter for that car type is greater than 0 (space available)
- If yes, decrement the counter and return
true
- If no, return
false
Using an array with index 0 unused and indices 1, 2, 3 corresponding to big, medium, and small makes the code extremely clean - we can directly use carType
as the index without any transformation. This gives us O(1) time complexity for parking operations and O(1) space complexity (since we only need to store 3 counts).
Solution Approach
The implementation uses a simulation approach with an array-based data structure to track parking space availability.
Data Structure:
- We use an array
cnt
of length 4 to store the number of available parking spaces cnt[0]
is unused (set to 0)cnt[1]
stores the number of available big parking spacescnt[2]
stores the number of available medium parking spacescnt[3]
stores the number of available small parking spaces
Initialization (__init__
method):
def __init__(self, big: int, medium: int, small: int):
self.cnt = [0, big, medium, small]
We create the array with index 0 set to 0 (unused), and indices 1, 2, 3 initialized with the given counts for big, medium, and small spaces respectively. This clever indexing allows us to use the carType
value directly as an array index.
Adding a Car (addCar
method):
def addCar(self, carType: int) -> bool:
if self.cnt[carType] == 0:
return False
self.cnt[carType] -= 1
return True
The algorithm follows these steps:
- Check if there's an available space by accessing
self.cnt[carType]
- If
self.cnt[carType] == 0
, no space is available, so returnFalse
- Otherwise, decrement the count by 1 to mark one space as occupied
- Return
True
to indicate successful parking
Time and Space Complexity:
- Time Complexity: O(1) for both initialization and
addCar
operations, as we're only accessing and updating array elements - Space Complexity: O(1) as we only store a fixed-size array of 4 elements regardless of input size
This simulation approach is optimal because it directly models the real-world scenario with minimal overhead and provides constant-time operations for all parking system functions.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example to illustrate how the parking system works:
Initial Setup:
parkingSystem = ParkingSystem(1, 2, 1)
This creates a parking lot with:
- 1 big parking space
- 2 medium parking spaces
- 1 small parking space
Internally, our array cnt
is initialized as: [0, 1, 2, 1]
cnt[0] = 0
(unused)cnt[1] = 1
(big spaces)cnt[2] = 2
(medium spaces)cnt[3] = 1
(small spaces)
Operation 1: Park a big car
parkingSystem.addCar(1) # Returns True
- We check
cnt[1]
which equals 1 (space available) - Decrement
cnt[1]
by 1:cnt[1] = 0
- Array becomes:
[0, 0, 2, 1]
- Return
True
(successfully parked)
Operation 2: Park a medium car
parkingSystem.addCar(2) # Returns True
- We check
cnt[2]
which equals 2 (space available) - Decrement
cnt[2]
by 1:cnt[2] = 1
- Array becomes:
[0, 0, 1, 1]
- Return
True
(successfully parked)
Operation 3: Park another big car
parkingSystem.addCar(1) # Returns False
- We check
cnt[1]
which equals 0 (no space available) - No changes to the array:
[0, 0, 1, 1]
- Return
False
(parking failed - no big spaces left)
Operation 4: Park a small car
parkingSystem.addCar(3) # Returns True
- We check
cnt[3]
which equals 1 (space available) - Decrement
cnt[3]
by 1:cnt[3] = 0
- Array becomes:
[0, 0, 1, 0]
- Return
True
(successfully parked)
Final State: After these operations, the parking lot has:
- 0 big spaces available (all occupied)
- 1 medium space available
- 0 small spaces available (all occupied)
The beauty of this approach is that the carType
parameter (1, 2, or 3) directly corresponds to the array index, making the code elegant and efficient with no need for conditional statements or mappings.
Solution Implementation
1class ParkingSystem:
2 def __init__(self, big: int, medium: int, small: int):
3 """
4 Initialize the parking system with given number of slots for each car type.
5
6 Args:
7 big: Number of slots for big cars (type 1)
8 medium: Number of slots for medium cars (type 2)
9 small: Number of slots for small cars (type 3)
10 """
11 # Store available slots for each car type
12 # Index 0 is unused, indices 1-3 correspond to car types 1-3
13 self.available_slots = [0, big, medium, small]
14
15 def addCar(self, carType: int) -> bool:
16 """
17 Attempt to park a car of the given type.
18
19 Args:
20 carType: Type of car (1=big, 2=medium, 3=small)
21
22 Returns:
23 True if parking was successful, False if no slots available
24 """
25 # Check if there are available slots for this car type
26 if self.available_slots[carType] == 0:
27 return False
28
29 # Decrement the available slots count for this car type
30 self.available_slots[carType] -= 1
31 return True
32
33
34# Your ParkingSystem object will be instantiated and called as such:
35# obj = ParkingSystem(big, medium, small)
36# param_1 = obj.addCar(carType)
37
1/**
2 * A parking system that manages parking spaces for three different car sizes.
3 * Car types are represented by integers: 1 for big, 2 for medium, 3 for small.
4 */
5class ParkingSystem {
6 // Array to store the count of available parking spaces for each car type
7 // Index 0 is unused, index 1 for big cars, index 2 for medium cars, index 3 for small cars
8 private int[] availableSpaces;
9
10 /**
11 * Initializes the parking system with the given number of parking spaces for each car type.
12 *
13 * @param big Number of parking spaces for big cars
14 * @param medium Number of parking spaces for medium cars
15 * @param small Number of parking spaces for small cars
16 */
17 public ParkingSystem(int big, int medium, int small) {
18 // Initialize array with index 0 as placeholder (unused)
19 // This allows direct mapping: carType 1 -> index 1, carType 2 -> index 2, etc.
20 availableSpaces = new int[] {0, big, medium, small};
21 }
22
23 /**
24 * Attempts to park a car of the specified type.
25 *
26 * @param carType The type of car (1: big, 2: medium, 3: small)
27 * @return true if the car was successfully parked, false if no space is available
28 */
29 public boolean addCar(int carType) {
30 // Check if there are available spaces for this car type
31 if (availableSpaces[carType] == 0) {
32 return false;
33 }
34
35 // Decrement the available space count for this car type
36 availableSpaces[carType]--;
37 return true;
38 }
39}
40
41/**
42 * Your ParkingSystem object will be instantiated and called as such:
43 * ParkingSystem obj = new ParkingSystem(big, medium, small);
44 * boolean param_1 = obj.addCar(carType);
45 */
46
1class ParkingSystem {
2public:
3 /**
4 * Constructor initializes the parking system with given capacity for each car type
5 * @param big - Number of available slots for big cars (type 1)
6 * @param medium - Number of available slots for medium cars (type 2)
7 * @param small - Number of available slots for small cars (type 3)
8 */
9 ParkingSystem(int big, int medium, int small) {
10 // Initialize available slots array
11 // Index 0 is unused (placeholder), indices 1-3 correspond to car types 1-3
12 available_slots_ = {0, big, medium, small};
13 }
14
15 /**
16 * Attempts to park a car of the given type
17 * @param carType - Type of car (1: big, 2: medium, 3: small)
18 * @return true if parking was successful, false if no slots available
19 */
20 bool addCar(int carType) {
21 // Check if there are available slots for this car type
22 if (available_slots_[carType] == 0) {
23 return false;
24 }
25
26 // Park the car by decrementing available slots
27 --available_slots_[carType];
28 return true;
29 }
30
31private:
32 // Stores the number of available parking slots for each car type
33 // Index 0: unused, Index 1: big cars, Index 2: medium cars, Index 3: small cars
34 std::vector<int> available_slots_;
35};
36
37/**
38 * Your ParkingSystem object will be instantiated and called as such:
39 * ParkingSystem* obj = new ParkingSystem(big, medium, small);
40 * bool param_1 = obj->addCar(carType);
41 */
42
1// Array to store the count of available parking spots for each car type
2// Index 0 is unused, Index 1: big cars, Index 2: medium cars, Index 3: small cars
3let parkingSpots: [number, number, number, number];
4
5/**
6 * Initializes the parking system with the given number of spots for each car type
7 * @param big - Number of parking spots for big cars
8 * @param medium - Number of parking spots for medium cars
9 * @param small - Number of parking spots for small cars
10 */
11function initializeParkingSystem(big: number, medium: number, small: number): void {
12 parkingSpots = [0, big, medium, small];
13}
14
15/**
16 * Attempts to park a car of the given type
17 * @param carType - Type of car (1: big, 2: medium, 3: small)
18 * @returns true if the car was successfully parked, false if no spots available
19 */
20function addCar(carType: number): boolean {
21 // Check if there are available spots for this car type
22 if (parkingSpots[carType] === 0) {
23 return false;
24 }
25
26 // Decrement the available spots count for this car type
27 parkingSpots[carType]--;
28 return true;
29}
30
Time and Space Complexity
Time Complexity: O(1)
The __init__
method performs a simple list initialization with 4 elements, which takes constant time O(1)
.
The addCar
method performs:
- One array access to check if
self.cnt[carType] == 0
-O(1)
- One array access and decrement operation
self.cnt[carType] -= 1
-O(1)
- Return statement -
O(1)
Since all operations in both methods are constant time operations, the overall time complexity is O(1)
.
Space Complexity: O(1)
The class uses a fixed-size list self.cnt
with exactly 4 elements (index 0 plus the three parking spot types). Regardless of the input values for big
, medium
, and small
, the space used remains constant at 4 integer values. The space does not grow with the input size, making the space complexity O(1)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Array Index Out of Bounds
One of the most common mistakes is not validating the carType
parameter in the addCar
method. If someone passes an invalid car type (like 0, 4, or negative numbers), the code will either crash with an IndexError or access incorrect array positions.
Problematic Code:
def addCar(self, carType: int) -> bool:
# No validation - will crash if carType is not 1, 2, or 3
if self.available_slots[carType] == 0:
return False
self.available_slots[carType] -= 1
return True
Solution:
def addCar(self, carType: int) -> bool:
# Validate car type first
if carType < 1 or carType > 3:
return False # Invalid car type
if self.available_slots[carType] == 0:
return False
self.available_slots[carType] -= 1
return True
2. Using Dictionary Instead of Array (Over-engineering)
Some developers might use a dictionary thinking it's more readable, but this adds unnecessary overhead for such a simple problem with fixed car types.
Over-engineered Code:
def __init__(self, big: int, medium: int, small: int):
# Using dictionary adds unnecessary complexity
self.available_slots = {
'big': big,
'medium': medium,
'small': small
}
self.type_map = {1: 'big', 2: 'medium', 3: 'small'}
def addCar(self, carType: int) -> bool:
car_size = self.type_map.get(carType)
if not car_size or self.available_slots[car_size] == 0:
return False
self.available_slots[car_size] -= 1
return True
Better Approach: Stick with the simple array solution as shown in the original code.
3. Forgetting to Handle Thread Safety
In a real-world scenario with concurrent access, multiple threads might try to park cars simultaneously, leading to race conditions.
Problem Scenario:
Two threads check available_slots[1] > 0
at the same time, both see it's 1, and both try to decrement, potentially resulting in negative values.
Solution for Thread Safety:
import threading
class ParkingSystem:
def __init__(self, big: int, medium: int, small: int):
self.available_slots = [0, big, medium, small]
self.lock = threading.Lock()
def addCar(self, carType: int) -> bool:
with self.lock:
if self.available_slots[carType] == 0:
return False
self.available_slots[carType] -= 1
return True
4. Not Considering Negative Initial Values
The constructor doesn't validate if the initial parking space counts are non-negative.
Solution:
def __init__(self, big: int, medium: int, small: int):
# Ensure non-negative values
self.available_slots = [0, max(0, big), max(0, medium), max(0, small)]
What is an advantages of top-down dynamic programming vs bottom-up dynamic programming?
Recommended Readings
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!