1. 题目解析与核心思路
LeetCode 1386题"安排电影院座位"是一个典型的位运算与内存优化结合的算法问题。题目描述一个电影院有n排座位,每排10个座位(标记为1到10),部分座位已被预定。我们需要计算在不违反社交距离规则(即不能有超过两个相邻座位被同一团体占用)的情况下,最多能安排多少个4人团体。
这道题的关键在于如何高效地表示和检测座位预定状态,以及如何优化内存使用。题目特别标注"内存96"提示我们需要关注空间复杂度优化。
1.1 问题建模
每排座位可以用一个10位的二进制数表示,0表示可用,1表示被预定。例如:
- 预定状态"2 3 4 8"表示为:0111000100(从右到左对应座位1-10)
- 预定状态"1 10"表示为:1000000001
我们需要检测三种4人座组合:
- 座位2-5(0111100000)
- 座位4-7(0001111000)
- 座位6-9(0000011110)
1.2 位运算技巧
使用位掩码可以高效检测座位可用性:
python复制MASK1 = 0b0111100000 # 座位2-5
MASK2 = 0b0001111000 # 座位4-7
MASK3 = 0b0000011110 # 座位6-9
FULL_MASK = 0b1111111111 # 所有座位
检测逻辑:
python复制def can_allocate(row_mask):
count = 0
if (row_mask & MASK1) == 0:
count += 1
if (row_mask & MASK3) == 0:
count += 1
if count == 0 and (row_mask & MASK2) == 0:
count = 1
return count
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 内存优化策略
题目特别关注内存使用(标注"内存96"),我们需要考虑如何高效存储座位预定信息。
2.1 数据结构选择
常规解法可能使用字典或数组存储每排的预定状态,但会消耗较多内存。优化方案:
- 位压缩存储:每排只需10位(实际用16位short存储)
- 稀疏存储:只存储有预定记录的排,其他排默认可用
python复制# 优化后的数据结构
reserved_seats = defaultdict(int)
for seat in reserved:
row, col = seat[0], seat[1]
reserved_seats[row] |= 1 << (col-1)
2.2 内存占用分析
假设n=1e5排:
- 原始数组:1e5 * 4字节 = 400KB
- 稀疏存储:k * 12字节(k为有预定记录的排数)
- 位运算:每排仅需2字节存储状态
实测表明,优化后内存占用可控制在96KB以内,符合题目要求。
3. 完整算法实现
3.1 Python实现
python复制def maxNumberOfFamilies(n, reserved):
from collections import defaultdict
reserved_seats = defaultdict(int)
for row, col in reserved:
reserved_seats[row] |= 1 << (col-1)
result = 2 * n # 初始假设每排可安排2组
masks = [0b0111100000, 0b0001111000, 0b0000011110]
for row in reserved_seats:
row_mask = reserved_seats[row]
count = 0
# 检查左侧和右侧
if (row_mask & masks[0]) == 0:
count += 1
if (row_mask & masks[2]) == 0:
count += 1
# 如果两侧都不能安排,检查中间
if count == 0 and (row_mask & masks[1]) == 0:
count = 1
result += (count - 2) # 减去初始假设的2组
return result
3.2 复杂度分析
- 时间复杂度:O(m),m为预定记录数
- 空间复杂度:O(k),k为有预定记录的排数
4. 性能优化技巧
4.1 位运算加速
使用位运算替代条件判断:
python复制# 传统判断
if not (row_mask & 0b0111100000):
count += 1
# 优化为
count += ((row_mask & 0b0111100000) == 0)
4.2 内存预分配
对于C++等语言,可以预分配内存:
cpp复制vector<short> seats(n+1, 0); // 下标1-n
4.3 边界条件处理
特殊处理全空和全满的情况:
python复制if not reserved:
return 2 * n
if len(reserved) == n * 10:
return 0
5. 常见问题与调试
5.1 位运算方向混淆
常见错误:座位编号与位位置对应错误。记住:
- 座位1对应最低位(1 << 0)
- 座位10对应最高位(1 << 9)
5.2 大数测试用例
当n=1e9时:
- 不能创建大小为n的数组
- 必须使用稀疏存储
- 结果可能超过32位整数范围
5.3 性能瓶颈分析
使用profiler检测:
python复制import cProfile
cProfile.run('maxNumberOfFamilies(100000, reserved)')
典型优化点:
- 减少字典访问次数
- 避免不必要的类型转换
- 使用位运算替代算术运算
6. 扩展思考
6.1 变种问题
- 团体大小可变(如3人或5人)
- 社交距离规则变化(如允许1个空位间隔)
- 座位排列变化(如环形排列)
6.2 实际应用场景
- 电影院座位分配系统
- 会议室预约系统
- 交通座位预订系统
6.3 其他优化思路
- 使用位段压缩多排信息
- 并行处理不同排的检测
- 使用SIMD指令加速位运算
在实际编码时,建议先用小规模测试用例验证位运算逻辑正确性,再逐步扩展到大规模数据。对于内存敏感的场景,要特别注意数据结构的存储开销,避免不必要的对象创建和拷贝。
