【力扣刷题】 1349.参加考试的最大学生数

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)

谈谈收获

  1. 看题解的时候看到了Python3的一个@cache的注解,猜测所有记忆化搜索应该有一个通用的套路,函数在不依赖外部变量时,或者相同的参数的外部依赖的值相同时,函数的返回值只与函数的参数有关,所以每次调用,在函数结束时,我们只需要记录函数的参数及其对应的返回值,将其记录到cache中(在这里面是memo字典),在执行函数之前查询对应的参数是否存在即可。

第一份代码没有用到状态压缩,将每次执行的状态保存在外部数组st中,由于相同的参数对应的外部数组st的值存在差异,所以这里不能使用记忆化搜索。如果要使用记忆化搜索,需要将外部状态数组压缩成二进制。

  1. 一些二进制运算技巧
    1. s & (s >> 1) 检查是否有相邻的1
    2. s = (s - 1) & site 依次枚举所有的情况
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值