Problem: 1349. 参加考试的最大学生数
思路
从左上角开始枚举所有的能够坐人的位置,将不能进行坐人的位置打上标记,并在此基础上再进行搜索下个位置
解题方法
dfs暴搜 + 状态压缩 + 记忆化搜索
dfs函数定义为:在当前行的当前状态下,能够坐下的最大学生数
将可以坐人的二进制位置标记为1,枚举每一行,对每一行的所有坐人的情况进行枚举,并将下一行可以坐人的位置传递给下一层dfs,对所有的情况取最大值
对函数的参数保存在memo字典中,如果下次调用时参数相同,则直接返回
具体实现参考了:
https://leetcode.cn/problems/maximum-students-taking-exam/solutions/2580043/jiao-ni-yi-bu-bu-si-kao-dong-tai-gui-hua-9y5k/?envType=daily-question&envId=2023-12-26 的代码
和灵茶山艾府大佬的代码不一样的是:
我是从上往下枚举状态
以及递归出口,我是在越界时退出,这样就可以少考虑大佬代码中,最后一层的情况
Code
代码只用了Python实现,复刷的时候可能会用别的语言
暴力dfs
class Solution(object):
def maxStudents(self, seats):
h, w = len(seats), len(seats[0])
st = [[0 for _ in range(w)] for _ in range(h)]
direction = [(0, -1), (0, 1), (1, -1), (1, 1), (0, 0)]
memo = {}
def check(y, x):
if 0 <= x < w and 0 <= y < h: return True
return False
def dfs(x, y, cnt):
# m = memo.get((x, y, cnt), -1)
# if m != -1: return m
res = cnt
for i in range(y, h):
for j in range(0, w):
if seats[i][j] == '.' and st[i][j] == 0:
for (ydir, xdir) in direction:
if check(i + ydir, j + xdir):
st[i + ydir][j + xdir] += 1
res = max(res, dfs(j + 1, i, cnt + 1))
for (ydir, xdir) in direction:
if check(i + ydir, j + xdir):
st[i + ydir][j + xdir] -= 1
# memo[(x, y, cnt)] = res
return res
return dfs(0, 0, 0)
class Solution(object):
def maxStudents(self, seats):
a = [sum(('.' == k) << i for i, k in enumerate(s)) for s in seats] # 列表推导式,将空位设置为1
memo = {}
def dfs(i, site, cnt):
m = memo.get((i, site, cnt), -1)
if m != -1: return m
if i == len(seats):
return cnt
s = site
res = -1
while s:
if(s & (s >> 1)) == 0:
t = a[i + 1] & ~(s << 1 | s >> 1) if i + 1 < len(seats) else -1
res = max(res, dfs(i + 1, t, cnt + bin(s).count('1')))
s = (s - 1) & site
res = max(res, dfs(i + 1, a[i + 1] if i + 1 < len(seats) else -1, cnt))
memo[(i, site, cnt)] = res
return res
return dfs(0, a[0], 0)
谈谈收获
- 看题解的时候看到了Python3的一个@cache的注解,猜测所有记忆化搜索应该有一个通用的套路,函数在不依赖外部变量时,或者相同的参数的外部依赖的值相同时,函数的返回值只与函数的参数有关,所以每次调用,在函数结束时,我们只需要记录函数的参数及其对应的返回值,将其记录到cache中(在这里面是memo字典),在执行函数之前查询对应的参数是否存在即可。
第一份代码没有用到状态压缩,将每次执行的状态保存在外部数组st中,由于相同的参数对应的外部数组st的值存在差异,所以这里不能使用记忆化搜索。如果要使用记忆化搜索,需要将外部状态数组压缩成二进制。
- 一些二进制运算技巧
- s & (s >> 1) 检查是否有相邻的1
- s = (s - 1) & site 依次枚举所有的情况