Problem
There is a party where n
friends numbered from 0
to n - 1
are attending. There is an infinite number of chairs in this party that are numbered from 0
to infinity
. When a friend arrives at the party, they sit on the unoccupied chair with the smallest number.
- For example, if chairs
0
,1
, and5
are occupied when a friend comes, they will sit on chair number2
.
When a friend leaves the party, their chair becomes unoccupied at the moment they leave. If another friend arrives at that same moment, they can sit in that chair.
You are given a 0-indexed 2D integer array times
where times[i] = [arrivali, leavingi]
, indicating the arrival and leaving times of the ith
friend respectively, and an integer targetFriend
. All arrival times are distinct.
Return the chair number that the friend numbered targetFriend
will sit on.
Examples
Example 1:
Input: times = [[1,4],[2,3],[4,6]], targetFriend = 1
Output: 1
Explanation:
- Friend 0 arrives at time 1 and sits on chair 0.
- Friend 1 arrives at time 2 and sits on chair 1.
- Friend 1 leaves at time 3 and chair 1 becomes empty.
- Friend 0 leaves at time 4 and chair 0 becomes empty.
- Friend 2 arrives at time 4 and sits on chair 0.
Since friend 1 sat on chair 1, we return 1.
Example 2:
Input: times = [[3,10],[1,5],[2,6]], targetFriend = 0
Output: 2
Explanation:
- Friend 1 arrives at time 1 and sits on chair 0.
- Friend 2 arrives at time 2 and sits on chair 1.
- Friend 0 arrives at time 3 and sits on chair 2.
- Friend 1 leaves at time 5 and chair 0 becomes empty.
- Friend 2 leaves at time 6 and chair 1 becomes empty.
- Friend 0 leaves at time 10 and chair 2 becomes empty.
Since friend 0 sat on chair 2, we return 2.
Solution
Video explanation
Here is the video explaining below methods in detail. Please check it out:
Method 1 - Using Map and Priority Queue
Here is the idea:
- Simulate the Chair Allocation: When a friend arrives, we need to find the smallest unoccupied chair. When they leave, that chair becomes available again.
- Two Events:
- Arrival events where a friend occupies the smallest available chair.
- Leaving events where a chair is freed up.
- Sorting: First, sort all events (both arrival and departure) by time. For events happening at the same time, handle departures before arrivals to ensure that any chair vacated is available immediately.
- Data Structures:
- Use a priority queue to keep track of the smallest available chairs.
- Use a map (or hashmap) to associate each friend with their allocated chair.
Here is the approach:
- Parse and sort the events.
- Use a priority queue to manage chair allocation.
- When processing arrivals, allocate the smallest available chair.
- When processing departures, mark the chair as available again.
- Return the chair number of the target friend.
Code
Java
public class Solution {
public int smallestChair(int[][] times, int targetFriend) {
// List to hold all events
List<int[]> events = new ArrayList<>();
// Create events for arrivals and departures
for (int i = 0; i < times.length; i++) {
events.add(new int[]{times[i][0], 1, i}); // Arrival event
events.add(new int[]{times[i][1], 0, i}); // Departure event
}
// Sort events: first by time, then by type (departure before arrival if same time)
events.sort((a, b) -> {
if (a[0] == b[0]) {
return Integer.compare(a[1], b[1]);
} else {
return Integer.compare(a[0], b[0]);
}
});
// Priority queue to track smallest available chairs
PriorityQueue<Integer> availableChairs = new PriorityQueue<>();
for (int i = 0; i < times.length; i++) {
availableChairs.add(i);
}
// Map to store which chair a friend is sitting on
Map<Integer, Integer> friendChairMap = new HashMap<>();
// Process each event
for (int[] event : events) {
int time = event[0];
boolean isArrival = event[1] == 1;
int friendIdx = event[2];
if (isArrival) {
int chair = availableChairs.poll(); // Get the smallest available chair
friendChairMap.put(friendIdx, chair); // Assign the chair to the friend
if (friendIdx == targetFriend) {
return chair; // If it's the target friend, return the chair number
}
} else {
availableChairs.add(friendChairMap.get(friendIdx)); // Free the chair
}
}
return -1; // Should not reach here if inputs are valid
}
}
Python
class Solution:
def smallestChair(self, times: List[List[int]], targetFriend: int) -> int:
# List to hold all events
events = []
# Create events for arrivals and departures
for i, (arrive, leave) in enumerate(times):
events.append((arrive, True, i)) # Arrival event
events.append((leave, False, i)) # Departure event
# Sort events: first by time, then by type (departure before arrival if same time)
events.sort(key=lambda x: (x[0], not x[1]))
# Priority queue to track smallest available chairs
available_chairs = list(range(len(times)))
heapq.heapify(available_chairs)
# Dictionary to store which chair a friend is sitting on
friendChairMap = {}
# Process each event
for time, is_arrival, friend_idx in events:
if is_arrival:
chair = heapq.heappop(available_chairs) # Get the smallest available chair
friendChairMap[friend_idx] = chair # Assign the chair to the friend
if friend_idx == targetFriend:
return chair # If it's the target friend, return the chair number
else:
heapq.heappush(available_chairs, friendChairMap[friend_idx]) # Free the chair
# Should not reach here if inputs are valid
return -1
Complexity
- ⏰ Time complexity:
O(n log n)
, due to sorting events and operations on the priority queue. - 🧺 Space complexity:
O(n)
for maintaining the priority queue and mapping.
Method 2 - Using Two Priority Queues
Here are the steps:
- We need to sort the times based on arrival time, which means we will loose the order of friends. So, before that, store the
arrivalTime
oftargetFriend
, since all the the arrival times are distinct this can be used to identify the targetFriend in sorted array. - Store all the available seats(one for each friend) in
minHeap
as available. Because we need to choose the min available chair number - Sort the times array based on arrival time.
- Maintain another minHeap to store leavingTime and occupiedSeat.
- loop through sorted array
- remove all the friends from the heap whose leavingTime is less than or equal to current arraival time and add the occupied seats back to available heap.
- if the current start is equal to targetStart return the min available seat.
- else add the current leaving time and min available seat to heap.
Code
Java
class Solution {
public int smallestChair(int[][] times, int targetFriend) {
// Time at which targetFriend arrives
int targetStart = times[targetFriend][0];
// Sort the times array based on arrival times
Arrays.sort(times, (a, b) -> a[0] - b[0]);
// Priority queue (min-heap) to store available chairs
PriorityQueue<Integer> available = new PriorityQueue<>();
for (int i = 0; i < times.length; ++i) {
available.offer(i);
}
// Priority queue (min-heap) to store departure times and associated chairs
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[0] - b[0]);
// Process each friend based on sorted arrival times
for (int i = 0; i < times.length; ++i) {
// Free up chairs based on departure times before the current arrival time
while (!pq.isEmpty() && pq.peek()[0] <= times[i][0]) {
available.offer(pq.poll()[1]);
}
// If we reach the target friend, break and return the smallest available chair
if (times[i][0] == targetStart) {
break;
}
// Assign the smallest available chair to the current friend and add their departure time to the priority queue
pq.offer(new int[]{times[i][1], available.poll()});
}
// Return the smallest available chair for the target friend
return available.peek();
}
}
Python
class Solution:
def smallestChair(self, times: List[List[int]], targetFriend: int) -> int:
# Time at which targetFriend arrives
targetStart = times[targetFriend][0]
# Sort the times array based on arrival times
times.sort(key=lambda x: x[0])
# Priority queue (min-heap) to store available chairs
available = list(range(len(times)))
heapq.heapify(available)
# Priority queue (min-heap) to store departure times and associated chairs
pq = []
# Process each friend based on sorted arrival times
for i in range(len(times)):
# Free up chairs based on departure times before the current arrival time
while pq and pq[0][0] <= times[i][0]:
heapq.heappush(available, heapq.heappop(pq)[1])
# If we reach the target friend, break and return the smallest available chair
if times[i][0] == targetStart:
break
# Assign the smallest available chair to the current friend and add their departure time to the priority queue
heapq.heappush(pq, (times[i][1], heapq.heappop(available)))
# Return the smallest available chair for the target friend
return available[0]
Complexity
- ⏰ Time complexity:
O(NNNXXXNNN)
- 🧺 Space complexity:
O(NNNXXX)