力扣:安排电影院座位

题目描述


如下图所示,电影院的观影厅中有 n 行座位,行编号从 1 到 n ,且每一行内总共有 10 个座位,列编号从 1 到 10 。
在这里插入图片描述
给你数组 reservedSeats ,包含所有已经被预约了的座位。比如说,researvedSeats[i]=[3,8] ,它表示第 3 行第 8 个座位被预约了。
请你返回 最多能安排多少个 4 人家庭 。4 人家庭要占据 同一行内连续 的 4 个座位。隔着过道的座位(比方说 [3,3] 和 [3,4])不是连续的座位,但是如果你可以将 4 人家庭拆成过道两边各坐 2 人,这样子是允许的。
力扣:1386.安排电影院座位

示例
在这里插入图片描述
输入:n = 3, reservedSeats = [ [ 1 , 2 ] , [ 1 , 3 ] , [ 1 , 8 ] , [2 , 6 ] , [ 3 , 1 ] , [ 3 , 10 ] ]
输出:4
解释:上图所示是最优的安排方案,总共可以安排 4 个家庭。蓝色的叉表示被预约的座位,橙色的连续座位表示一个 4 人家庭。

题目分析


参考该题官方题解
按照题意的要求,安排一个 4 人的家庭,有以下三种情况:

  • 位置 2 - 3 - 4 - 5
  • 位置 4 - 5 - 6 - 7
  • 位置 6 - 7 - 8 - 9

  因此每一排的位置 1 和 位置 10 是否被预定,对结果没有任何的影响,可以直接忽略考虑;如果一排没有位置被预约,那么恰好可以安排两个家庭,但只要有一个被预定,那么这一排至多还能安排一个家庭。
  剩下的位置可以采用 8 个二进制位来表示一排座位,分别表示座位 2 ~ 9 的预约情况,如果位置 i 的作为别预约 , 那么第 i - 2 个二进制位置 1 , 否则为 0 。
  例如 第一排:预约了位置 ( 2-3-8 ) 通过二进制表示为 (010000110)
  存储结构采用哈希映射(HashMap)来存储每一排以及它们的二进制数。对于哈希映射中的每个键值对,键表示电影院中的一排,值表示这一排对应的二进制数。而只要某一排出现在 HashMap 的键中,说明该排至多能安排一个家庭入座, 没有出现在 键 中,则该排能安排两个家庭入座。
  在处理完了所有的预约之后,遍历哈希映射,对于一个键值对 (row,bitmask) 中的 bitmask 二进制数进行分析,判断是否符合上述给出的三种情况中的一种。

分析:对于安排位置 2-3-4-5 给一个家庭时有, 先给定 left = 0b11110000 ,如果 bitmask | left == left 说明 2-3-4-5 均没有被预约,此时可分配给一个家庭。
同理可得: 安排位置 4-5-6-7 时有 , middle = 0b11000011 ; 安排 5-6-7-8 时有, right = 0b00001111

AC代码:

class Solution {
    public int maxNumberOfFamilies(int n, int[][] reservedSeats) {
        // 因为座位 1 和 10 对结果不产生影响 , 采用二进制来表示 2 ~ 9 剩余的 8 个位置
        int left = 0b11110000; 
        int middle = 0b11000011;
        int right = 0b00001111;

        // 通过 Map 来存储一行
        Map<Integer , Integer> cinema = new HashMap<>();
        for(int[] seat : reservedSeats){
            if(seat[1] >= 2 && seat[1] <= 9){
                int position = cinema.containsKey(seat[0]) ? cinema.get(seat[0]) : 0 ;
                int value = position | (1 << (seat[1] - 2)); // 预约对应的位置, 将 1 左移相应的位置,例如预约 3 ,需要将其左移一位
                cinema.put(seat[0] , value);
            }
        }

        // 统计满足条件的 四连坐
        int ans = (n - cinema.size()) * 2; // 没有被预定的一行,有两个序列是满足条件的
        for(Map.Entry<Integer , Integer> entry : cinema.entrySet()){
            int row = entry.getValue();
            if (((row | left) == left) || ((row | middle) == middle) || ((row | right) == right)) {
                ans ++;
            }
        }
        return ans;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值