The "Cinema Seat Allocation" problem asks you to determine the maximum number of 4-person families that can be seated in a cinema, given certain seat reservations.
The cinema has n
rows, each with 10 seats labeled from 1 to 10. Some seats are already reserved and cannot be used. A family of 4 can be seated together if they occupy four consecutive seats in the same row, and their block of seats must be one of these three possible blocks:
n
: total number of rowsreservedSeats
: a list of reserved seat positions, where each reservation is a pair [row, seatNumber]
To solve this problem, let's start by considering the brute-force approach: for every row, check every possible block of 4 consecutive seats and see if it is available. Since there are only three valid blocks per row, this is manageable.
However, with potentially up to 109 rows, iterating through every seat in every row would be too slow. The key observation is that only rows with reserved seats affect the answer, because in unreserved rows, both the left and right blocks are guaranteed to be available, and thus two families can always be seated.
So, we shift our focus to:
Here’s a step-by-step breakdown of the optimized algorithm:
n
.
Example Input:
n = 3
reservedSeats = [[1,2],[1,3],[1,8],[2,6],[3,1],[3,10]]
Step-by-step:
Brute-force approach:
The "Cinema Seat Allocation" problem is solved efficiently by focusing only on rows with reserved seats and determining which family blocks remain available. By using a hash map to group reservations per row, we avoid unnecessary checks and achieve optimal performance even for large numbers of rows. The solution elegantly combines simple block checks with efficient data structures for a fast and clear result.
class Solution:
def maxNumberOfFamilies(self, n, reservedSeats):
from collections import defaultdict
reserved = defaultdict(set)
for row, seat in reservedSeats:
reserved[row].add(seat)
ans = 0
for row in reserved:
seats = reserved[row]
left = all(s not in seats for s in [2,3,4,5])
right = all(s not in seats for s in [6,7,8,9])
middle = all(s not in seats for s in [4,5,6,7])
if left and right:
ans += 2
elif left or right or middle:
ans += 1
ans += 2 * (n - len(reserved))
return ans
class Solution {
public:
int maxNumberOfFamilies(int n, vector<vector<int>>& reservedSeats) {
unordered_map<int, unordered_set<int>> reserved;
for (auto &seat : reservedSeats) {
reserved[seat[0]].insert(seat[1]);
}
int ans = 0;
for (auto &kv : reserved) {
auto &seats = kv.second;
bool left = true, right = true, middle = true;
for (int s : {2,3,4,5}) if (seats.count(s)) left = false;
for (int s : {6,7,8,9}) if (seats.count(s)) right = false;
for (int s : {4,5,6,7}) if (seats.count(s)) middle = false;
if (left && right)
ans += 2;
else if (left || right || middle)
ans += 1;
}
ans += 2 * (n - reserved.size());
return ans;
}
};
import java.util.*;
class Solution {
public int maxNumberOfFamilies(int n, int[][] reservedSeats) {
Map<Integer, Set<Integer>> reserved = new HashMap<>();
for (int[] seat : reservedSeats) {
reserved.computeIfAbsent(seat[0], k -> new HashSet<>()).add(seat[1]);
}
int ans = 0;
for (Set<Integer> seats : reserved.values()) {
boolean left = true, right = true, middle = true;
for (int s : new int[]{2,3,4,5}) if (seats.contains(s)) left = false;
for (int s : new int[]{6,7,8,9}) if (seats.contains(s)) right = false;
for (int s : new int[]{4,5,6,7}) if (seats.contains(s)) middle = false;
if (left && right)
ans += 2;
else if (left || right || middle)
ans += 1;
}
ans += 2 * (n - reserved.size());
return ans;
}
}
var maxNumberOfFamilies = function(n, reservedSeats) {
const reserved = new Map();
for (const [row, seat] of reservedSeats) {
if (!reserved.has(row)) reserved.set(row, new Set());
reserved.get(row).add(seat);
}
let ans = 0;
for (const seats of reserved.values()) {
let left = [2,3,4,5].every(s => !seats.has(s));
let right = [6,7,8,9].every(s => !seats.has(s));
let middle = [4,5,6,7].every(s => !seats.has(s));
if (left && right) ans += 2;
else if (left || right || middle) ans += 1;
}
ans += 2 * (n - reserved.size);
return ans;
};