You are given a 2D array seats
representing a classroom of students about to take an exam. Each element of seats
is either '.'
(an available seat) or '#'
(a broken seat). The classroom has m
rows and n
columns.
A student can sit in a seat if it is available. However, to prevent cheating, no two students can sit in seats that are adjacent horizontally or diagonally (i.e., a student cannot sit directly to the left, right, upper-left, or upper-right of another student).
Your task is to determine the maximum number of students that can take the exam without violating the above constraints. Each seat can be used at most once, and you cannot reuse elements.
At first glance, the problem appears to be a variant of the classic "maximum independent set" problem on a grid, with additional adjacency constraints. A brute-force approach would be to try every possible combination of students sitting in available seats and check if the constraints are satisfied. However, the number of combinations grows exponentially with the number of seats, making brute-force infeasible for larger grids.
To solve this efficiently, we need a way to represent the state of each row and quickly check for conflicts. Since each seat can be either occupied or not, we can represent each row as a bitmask, where each bit indicates whether a student sits in a particular seat. We can then use dynamic programming (DP) to build up solutions row by row, only considering valid seatings and keeping track of the best possible arrangement so far.
The key insight is to use bitmasking to efficiently encode seat assignments and to use DP to avoid recalculating overlapping subproblems.
Let's break down the steps to solve the problem efficiently:
1
means a student sits in that seat, and 0
means the seat is empty or broken.
dp[row][mask]
represents the maximum number of students for the first row
rows, ending with seating configuration mask
on the current row.
This approach leverages bitmasking for fast adjacency checks and DP for optimal substructure, making it much more efficient than brute-force.
Suppose seats = [[".", "#", ".", ".", "#"], [".", ".", "#", ".", "."], ["#", ".", "#", ".", "#"]]
.
10100
(student in seat 0 and 2) is valid.
10100
, row 1 cannot have a student in seat 1 or 3.
For this example, the optimal arrangement allows 4 students without violating the constraints.
class Solution:
def maxStudents(self, seats):
m, n = len(seats), len(seats[0])
valid = []
for row in seats:
mask = 0
for j, c in enumerate(row):
if c == '.':
mask |= (1 << j)
valid.append(mask)
from collections import defaultdict
dp = {0: 0}
for i in range(m):
ndp = defaultdict(int)
for curr in range(1 << n):
if (curr & ~valid[i]) != 0: continue
if (curr & (curr << 1)) != 0: continue
for prev in dp:
if (curr & (prev << 1)) != 0: continue
if (curr & (prev >> 1)) != 0: continue
ndp[curr] = max(ndp[curr], dp[prev] + bin(curr).count('1'))
dp = ndp
return max(dp.values()) if dp else 0
class Solution {
public:
int maxStudents(vector<vector<char>>& seats) {
int m = seats.size(), n = seats[0].size();
vector<int> valid(m, 0);
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (seats[i][j] == '.') valid[i] |= (1 << j);
}
}
unordered_map<int, int> dp;
dp[0] = 0;
for (int i = 0; i < m; ++i) {
unordered_map<int, int> ndp;
for (int curr = 0; curr < (1 << n); ++curr) {
if ((curr & ~valid[i]) != 0) continue;
if ((curr & (curr << 1)) != 0) continue;
for (auto& p : dp) {
int prev = p.first;
if ((curr & (prev << 1)) != 0) continue;
if ((curr & (prev >> 1)) != 0) continue;
int cnt = __builtin_popcount(curr);
ndp[curr] = max(ndp[curr], dp[prev] + cnt);
}
}
dp = ndp;
}
int res = 0;
for (auto& p : dp) res = max(res, p.second);
return res;
}
};
class Solution {
public int maxStudents(char[][] seats) {
int m = seats.length, n = seats[0].length;
int[] valid = new int[m];
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (seats[i][j] == '.') valid[i] |= (1 << j);
}
}
Map<Integer, Integer> dp = new HashMap<>();
dp.put(0, 0);
for (int i = 0; i < m; ++i) {
Map<Integer, Integer> ndp = new HashMap<>();
for (int curr = 0; curr < (1 << n); ++curr) {
if ((curr & ~valid[i]) != 0) continue;
if ((curr & (curr << 1)) != 0) continue;
for (int prev : dp.keySet()) {
if ((curr & (prev << 1)) != 0) continue;
if ((curr & (prev >> 1)) != 0) continue;
int cnt = Integer.bitCount(curr);
ndp.put(curr, Math.max(ndp.getOrDefault(curr, 0), dp.get(prev) + cnt));
}
}
dp = ndp;
}
int res = 0;
for (int v : dp.values()) res = Math.max(res, v);
return res;
}
}
var maxStudents = function(seats) {
let m = seats.length, n = seats[0].length;
let valid = new Array(m).fill(0);
for (let i = 0; i < m; ++i) {
for (let j = 0; j < n; ++j) {
if (seats[i][j] === '.') valid[i] |= (1 << j);
}
}
let dp = new Map();
dp.set(0, 0);
for (let i = 0; i < m; ++i) {
let ndp = new Map();
for (let curr = 0; curr < (1 << n); ++curr) {
if ((curr & ~valid[i]) !== 0) continue;
if ((curr & (curr << 1)) !== 0) continue;
for (let [prev, val] of dp.entries()) {
if ((curr & (prev << 1)) !== 0) continue;
if ((curr & (prev >> 1)) !== 0) continue;
let cnt = curr.toString(2).split('1').length - 1;
ndp.set(curr, Math.max(ndp.get(curr) || 0, val + cnt));
}
}
dp = ndp;
}
let res = 0;
for (let v of dp.values()) res = Math.max(res, v);
return res;
};
Brute-force: The brute-force approach would try every subset of available seats, leading to O(2^{m \times n})
time, which is not feasible for even moderate grid sizes.
Optimized DP Approach:
2^n
possible seatings (bitmasks).
O(2^n \times 2^n)
.
O(m \times 2^n \times 2^n)
= O(m \times 4^n)
.
2^n
DP states, so O(2^n)
space.
This is efficient for n \leq 8
(as per Leetcode constraints), making the approach practical.
The problem challenges us to maximize the number of students taking an exam in a classroom with adjacency constraints. By representing seat arrangements with bitmasks and using dynamic programming to build up solutions row by row, we efficiently avoid redundant calculations and ensure all constraints are respected. The key insight is leveraging bit manipulation for fast state checks and DP for optimal substructure, resulting in an elegant and performant solution.