安排电影院座位
难度:
标签:
题目描述
如上图所示,电影院的观影厅中有 n
行座位,行编号从 1 到 n
,且每一行内总共有 10 个座位,列编号从 1 到 10 。
给你数组 reservedSeats
,包含所有已经被预约了的座位。比如说,reservedSeats[i]=[3,8]
,它表示第 3 行第 8 个座位被预约了。
请你返回 最多能安排多少个 4 人家庭 。4 人家庭要占据 同一行内连续 的 4 个座位。隔着过道的座位(比方说 [3,3] 和 [3,4])不是连续的座位,但是如果你可以将 4 人家庭拆成过道两边各坐 2 人,这样子是允许的。
示例 1:
输入:n = 3, reservedSeats = [[1,2],[1,3],[1,8],[2,6],[3,1],[3,10]] 输出:4 解释:上图所示是最优的安排方案,总共可以安排 4 个家庭。蓝色的叉表示被预约的座位,橙色的连续座位表示一个 4 人家庭。
示例 2:
输入:n = 2, reservedSeats = [[2,1],[1,8],[2,6]] 输出:2
示例 3:
输入:n = 4, reservedSeats = [[4,3],[1,4],[4,6],[1,7]] 输出:4
提示:
1 <= n <= 10^9
1 <= reservedSeats.length <= min(10*n, 10^4)
reservedSeats[i].length == 2
1 <= reservedSeats[i][0] <= n
1 <= reservedSeats[i][1] <= 10
- 所有
reservedSeats[i]
都是互不相同的。
代码结果
运行时间: 66 ms, 内存: 19.6 MB
/*
* 思路:
* 1. 使用 Java Stream API 处理 reservedSeats 数组,将其转为一个 Map。
* 2. 对于每一行,检查是否可以安排 4 人家庭在三个可能的位置:
* - 座位 2 到 5
* - 座位 4 到 7
* - 座位 6 到 9
* 3. 根据每一行可以安排的 4 人家庭数量进行累加。
*/
import java.util.*;
import java.util.stream.*;
public class CinemaSeatAllocationStream {
public int maxNumberOfFamilies(int n, int[][] reservedSeats) {
Map<Integer, Set<Integer>> reservedMap = Arrays.stream(reservedSeats)
.collect(Collectors.groupingBy(seat -> seat[0], Collectors.mapping(seat -> seat[1], Collectors.toSet())));
int maxFamilies = reservedMap.values().stream().mapToInt(reserved -> {
boolean canPlaceLeft = !reserved.contains(2) && !reserved.contains(3) && !reserved.contains(4) && !reserved.contains(5);
boolean canPlaceMiddle = !reserved.contains(4) && !reserved.contains(5) && !reserved.contains(6) && !reserved.contains(7);
boolean canPlaceRight = !reserved.contains(6) && !reserved.contains(7) && !reserved.contains(8) && !reserved.contains(9);
int count = 0;
if (canPlaceLeft) count++;
if (canPlaceRight) count++;
else if (canPlaceMiddle) count++;
return count;
}).sum();
return maxFamilies + 2 * (n - reservedMap.size());
}
}
解释
方法:
此题解使用了位操作和哈希表来有效地计算最多可以安排的4人家庭数量。首先,使用哈希表('tab')记录那些有至少一个被预订的座位的行,键是行号,值是一个整数,对应于行中被预订的座位的位标记。仅关注第2到第9列的座位,因为第1列和第10列的座位无法容纳一个完整的4人家庭。使用位操作将座位映射到一个8位的整数中。然后,对于那些没有任何预订记录的行,因为每行可以容纳两个4人家庭,所以简单地将这些行的家庭数量乘以2加到结果中。对于有预订记录的行,检查通过位掩码判断是否可以安排家庭。如果能在左侧(2-5座)、右侧(6-9座)或中间(4-7座)安排,则相应地增加计数。如果一行能同时在左侧和右侧安排家庭,则可以安排两个家庭,否则检查是否可以在中间安排一个家庭。
时间复杂度:
O(m)
空间复杂度:
O(m)
代码细节讲解
🦆
在位操作中,为什么选择将第2到第9列的座位映射到一个8位的整数,而不包含第1列和第10列?
▷🦆
位掩码定义中的`l`, `r`, `m`分别表示哪些座位?具体的位值`0b00001111`, `0b11110000`, `0b11000011`是如何确定的?
▷🦆
为什么在处理完全没有被预订的行时,可以直接假定每行可以安排两个家庭?
▷🦆
算法中如何处理一行中已经有部分座位被预订的情况?特别是在检查能否安排家庭时使用的逻辑是什么?
▷