Description
Given a m * n matrix seats that represent seats distributions in a classroom. If a seat is broken, it is denoted by '#' character otherwise it is denoted by a '.' character.
Students can see the answers of those sitting next to the left, right, upper left and upper right, but he cannot see the answers of the student sitting directly in front or behind him. Return the maximum number of students that can take the exam together without any cheating being possible.
Students must be placed in seats in good condition.
Example 1:
Input: seats = [["#",".","#","#",".","#"], [".","#","#","#","#","."], ["#",".","#","#",".","#"]] Output: 4 Explanation: Teacher can place 4 students in available seats so they don't cheat on the exam.
Example 2:
Input: seats = [[".","#"], ["#","#"], ["#","."], ["#","#"], [".","#"]] Output: 3 Explanation: Place all students in available seats.
Example 3:
Input: seats = [["#",".",".",".","#"], [".","#",".","#","."], [".",".","#",".","."], [".","#",".","#","."], ["#",".",".",".","#"]] Output: 10 Explanation: Place students in available seats in column 1, 3 and 5.
Constraints:
seatscontains only characters'.' and'#'.m == seats.lengthn == seats[i].length1 <= m <= 81 <= n <= 8
Solutions
Solution 1: State Compression + Memoization Search
We notice that each seat has two states: selectable and non-selectable. Therefore, we can use a binary number to represent the seat state of each row, where 1 represents selectable, and 0 represents non-selectable. For example, for the first row in Example 1, we can represent it as 010010. Therefore, we convert the initial seats into a one-dimensional array ss, where ss[i] represents the seat state of the ith row.
Next, we design a function dfs(seat, i), which represents the maximum number of students that can be accommodated starting from the ith row, and the seat state of the current row is seat.
We can enumerate all the seat selection states mask of the ith row, and judge whether mask meets the following conditions:
- The state mask cannot select seats outside of seat;
- The state mask cannot select adjacent seats.
If the conditions are met, we calculate the number of seats selected in the current row cnt. If it is the last row, update the return value of the function, that is, ans = max(ans, cnt). Otherwise, we continue to recursively solve the maximum number of the next row. The seat state of the next row is nxt = ss[i + 1], and we need to exclude the left and right sides of the selected seats in the current row. Then we recursively solve the maximum number of the next row, that is, ans = max(ans, cnt + dfs(nxt, i + 1)).
Finally, we return ans as the return value of the function.
To avoid repeated calculations, we can use memoization search to save the return value of the function dfs(seat, i) in a two-dimensional array f, where f[seat][i] represents the maximum number of students that can be accommodated starting from the ith row, and the seat state of the current row is seat.
The time complexity is O(4n × n × m), and the space complexity is O(2n × m). Where m and n are the number of rows and columns of the seats, respectively.
class Solution: def maxStudents(self, seats: List[List[str]]) -> int: def f(seat: List[str]) -> int: mask = 0 for i, c in enumerate(seat): if c == '.': mask |= 1 << i return mask @cache def dfs(seat: int, i: int) -> int: ans = 0 for mask in range(1 << n): if (seat | mask) != seat or (mask & (mask << 1)): continue cnt = mask.bit_count() if i == len(ss) - 1: ans = max(ans, cnt) else: nxt = ss[i + 1] nxt &= ~(mask << 1) nxt &= ~(mask >> 1) ans = max(ans, cnt + dfs(nxt, i + 1)) return ans n = len(seats[0]) ss = [f(s) for s in seats] return dfs(ss[0], 0)(code-box)
