位运算题目:安排电影院座位
文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 解法
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:安排电影院座位
出处:1386. 安排电影院座位
难度
7 级
题目描述
要求
电影院的观影厅中有 n \texttt{n} n 行座位,行编号从 1 \texttt{1} 1 到 n \texttt{n} n,每一行有 10 \texttt{10} 10 个座位,列编号从 1 \texttt{1} 1 到 10 \texttt{10} 10。如上图所示。
给定数组 reservedSeats \texttt{reservedSeats} reservedSeats,包含所有已经被预约了的座位。例如, researvedSeats[i] = [3,8] \texttt{researvedSeats[i] = [3,8]} researvedSeats[i] = [3,8] 表示第 3 \texttt{3} 3 行第 8 \texttt{8} 8 个座位被预约了。
返回可以安排入座的四人家庭的最大数量。四人家庭要占据同一行的连续四个座位。隔着过道的座位(例如 [3,3] \texttt{[3,3]} [3,3] 和 [3,4] \texttt{[3,4]} [3,4])不是连续的座位,但是如果可以将四人家庭拆成过道两边各坐两人,也是允许的。
示例
示例 1:
输入: n = 3, reservedSeats = [[1,2],[1,3],[1,8],[2,6],[3,1],[3,10]] \texttt{n = 3, reservedSeats = [[1,2],[1,3],[1,8],[2,6],[3,1],[3,10]]} n = 3, reservedSeats = [[1,2],[1,3],[1,8],[2,6],[3,1],[3,10]]
输出: 4 \texttt{4} 4
解释:上图所示是最优的安排方案,总共可以安排 4 \texttt{4} 4 个四人家庭。蓝色的叉表示被预约的座位,橙色的连续座位表示一个四人家庭。
示例 2:
输入: n = 2, reservedSeats = [[2,1],[1,8],[2,6]] \texttt{n = 2, reservedSeats = [[2,1],[1,8],[2,6]]} n = 2, reservedSeats = [[2,1],[1,8],[2,6]]
输出: 2 \texttt{2} 2
示例 3:
输入: n = 4, reservedSeats = [[4,3],[1,4],[4,6],[1,7]] \texttt{n = 4, reservedSeats = [[4,3],[1,4],[4,6],[1,7]]} n = 4, reservedSeats = [[4,3],[1,4],[4,6],[1,7]]
输出: 4 \texttt{4} 4
数据范围
- 1 ≤ n ≤ 10 9 \texttt{1} \le \texttt{n} \le \texttt{10}^\texttt{9} 1≤n≤109
- 1 ≤ reservedSeats.length ≤ min(10 × n, 10 4 ) \texttt{1} \le \texttt{reservedSeats.length} \le \texttt{min(10} \times \texttt{n, 10}^\texttt{4}\texttt{)} 1≤reservedSeats.length≤min(10×n, 104)
- reservedSeats[i].length = 2 \texttt{reservedSeats[i].length} = \texttt{2} reservedSeats[i].length=2
- 1 ≤ reservedSeats[i][0] ≤ n \texttt{1} \le \texttt{reservedSeats[i][0]} \le \texttt{n} 1≤reservedSeats[i][0]≤n
- 1 ≤ reservedSeats[i][1] ≤ 10 \texttt{1} \le \texttt{reservedSeats[i][1]} \le \texttt{10} 1≤reservedSeats[i][1]≤10
- 所有 reservedSeats[i] \texttt{reservedSeats[i]} reservedSeats[i] 各不相同
解法
思路和算法
由于电影院的座位行数 n n n 的最大值是 1 0 9 10^9 109,因此不能遍历电影院座位的每一行,而是需要根据已经被预约的座位计算可以安排入座的四人家庭的最大数量。
由于电影院座位的每一行有 10 10 10 个座位,因此对于每一行可以使用一个二进制数 mask \textit{mask} mask 表示该行被预约的座位。由于座位编号是 1 1 1 到 10 10 10,因此 mask \textit{mask} mask 使用 11 11 11 位二进制数表示,对于 1 ≤ i ≤ 10 1 \le i \le 10 1≤i≤10, mask \textit{mask} mask 的从低到高的第 i i i 位表示该行编号为 i i i 的座位是否被预约, 1 1 1 表示被预约, 0 0 0 表示未被预约, mask \textit{mask} mask 的最低位一定是 0 0 0,因为没有编号为 0 0 0 的座位。遍历数组 reservedSeats \textit{reservedSeats} reservedSeats 之后即可得到每一行被预约的座位,使用哈希表记录数组 reservedSeats \textit{reservedSeats} reservedSeats 中出现的每一行对应的 mask \textit{mask} mask。
对于没有在哈希表中出现的行,每一行的所有座位都未被预约,因此该行最多可以安排两个四人家庭入座。对于在哈希表中出现的行,每一行考虑两种安排四人家庭入座的方案,一是将左边座位 2 2 2 到 5 5 5 和右边座位 6 6 6 到 9 9 9 各安排一个四人家庭入座,二是将中间座位 4 4 4 到 7 7 7 安排一个四人家庭入座。
对于第一种方案,如果座位 2 2 2 到 5 5 5 都未被预约则可以安排一个四人家庭入座左边座位,如果座位 6 6 6 到 9 9 9 都未被预约则可以安排一个四人家庭入座右边座位,分别判断左边座位和右边座位是否可以安排四人家庭入座,得到可以安排入座的四人家庭数。
对于第二种方案,如果座位 4 4 4 到 7 7 7 都未被预约则可以安排一个四人家庭入座中间座位,判断中间座位是否可以安排四人家庭入座,得到可以安排入座的四人家庭数。
两种方案中取可以安排入座的四人家庭数的最大值,即为该行可以安排入座的四人家庭数的最大值。
遍历所有在哈希表中出现的行之后,即可得到整个电影院可以安排入座的四人家庭的最大数量。
对于每一行计算两种方案下可以安排入座的四人家庭数都可以使用位运算实现。具体做法是定义三个常量 MASK_LEFT \textit{MASK\_LEFT} MASK_LEFT、 MASK_RIGHT \textit{MASK\_RIGHT} MASK_RIGHT 和 MASK_MIDDLE \textit{MASK\_MIDDLE} MASK_MIDDLE 分别表示左边座位、右边座位和中间座位的二进制表示。将该行对应的 mask \textit{mask} mask 按位取反之后分别和每个常量计算按位与的结果,如果结果等于该常量本身则表示可以安排一个四人家庭入座该常量对应的四个座位。例如,如果 mask \textit{mask} mask 按位取反之后和 MASK_LEFT \textit{MASK\_LEFT} MASK_LEFT 按位与的结果等于 MASK_LEFT \textit{MASK\_LEFT} MASK_LEFT,则表示左边座位(即座位 2 2 2 到 5 5 5)可以安排一个四人家庭入座。
代码
class Solution {public int maxNumberOfFamilies(int n, int[][] reservedSeats) {final int MASK_LEFT = 0b00000111100;final int MASK_RIGHT = 0b01111000000;final int MASK_MIDDLE = 0b00011110000;Map<Integer, Integer> masks = new HashMap<Integer, Integer>();for (int[] reservedSeat : reservedSeats) {int row = reservedSeat[0], label = reservedSeat[1];masks.put(row, masks.getOrDefault(row, 0) | (1 << label));}int total = 2 * (n - masks.size());Set<Map.Entry<Integer, Integer>> entries = masks.entrySet();for (Map.Entry<Integer, Integer> entry : entries) {int mask = entry.getValue();int count1 = 0, count2 = 0;if ((~mask & MASK_LEFT) == MASK_LEFT) {count1++;}if ((~mask & MASK_RIGHT) == MASK_RIGHT) {count1++;}if ((~mask & MASK_MIDDLE) == MASK_MIDDLE) {count2++;}total += Math.max(count1, count2);}return total;}
}
复杂度分析
-
时间复杂度: O ( m ) O(m) O(m),其中 m m m 是数组 reservedSeats \textit{reservedSeats} reservedSeats 的长度。需要遍历每个被预约的座位计算每一行对应的二进制数并存入哈希表,然后遍历哈希表根据每一行对应的二进制数计算可以安排入座的四人家庭的最大数量,由于遍历每个被预约的座位以及遍历哈希表中的每一行的操作的时间都是 O ( 1 ) O(1) O(1),因此时间复杂度是 O ( m ) O(m) O(m)。
-
空间复杂度: O ( m ) O(m) O(m),其中 m m m 是数组 reservedSeats \textit{reservedSeats} reservedSeats 的长度。空间复杂度主要取决于哈希表,哈希表中的记录数不超过 m m m。