第25场双周赛
第四题
这道题可以按照回溯法的思路暴力结局,列举出来所有的可能佩戴方法。但是这种方法的复杂度较高,并不是最优解。
这里我们换一种思路,同样是回溯法,相比于给每个人佩戴帽子,每个人都有很多种选择,不如把问题转变成给帽子选择人。一共40顶帽子,每一个帽子都分为有人戴和没人戴。且只能被一个人拥有。因此我们考虑考虑变成背包问题,首先依次遍历40顶帽子(戴or不戴),在内层循环中遍历每一个人。
40顶帽子,最多10个人,这里有两个维度的数据。做如果回溯的话,有两条路径:
(1)10个人,每个人依次选择一个帽子。
(2)40顶帽子,每个帽子尝试分配给每个可能的人。
这里前一个状态和后一个状态之间是有关联的。对于不同的路径
(1)前一个状态选过的帽子,后一个状态不能再选了。
(2)前一个状态选过的人,后一个状态不能再选了。
但是因为集合不可hash,所以集合不能作为我们状态记录缓存的key。同时,我们也需要一个能在常数时间判断数据是否可用的方式,这里可以用另一种方式,bit位。对于不同的路径:
(1)第n个bit位代表帽子是否被选过
(2)第n个bit位代表人是否已经有帽子了
这个时候路径(2)的优势就体现了,因为最多10个人,可以在一个32bit的整数内表示,而路径(1)要40个bit。
同时,我们采用1<<n
来表示出来40顶帽子的状态,初始全部是0。检验第k顶帽子有没有人戴只需要判断(1<<(k-1)&hat
from functools import lru_cache
class Solution:
def numberWays(self, hats: List[List[int]]) -> int:
# 总人数
n = len(hats)
dic = collections.defaultdict(list)
for i in range(n):
for hat in hats[i]:
dic[hat].append(i)
@lru_cache(None)
def dp(cur, pos):
# cur 代表当前轮到第cur顶帽子可供选择
# pos 代表当前戴帽的人有哪些,为二进制压缩状态形式
# 首先,如果当前所有人都