1125.最小的必要团队

题目描述

你规划了一个技能清单skills,准备从备选人员中选择,
给了一个人员名单列表people,其中元素people[i]表示第i个人具备的技能。
提示:

  • skills中的元素互不相同
  • people[i]中的技能都在skills范围内
  • 技能列表长满足 1到16
f1-记忆化搜索+状态压缩

基本分析

  1. 技能的数量最大为16,暗示什么?可以用一个长度不超过16的二进制数表示每个技能是不是已经有人掌握
  2. 不添加记忆化和添加记忆化在搜索上的区别在哪?
    • 不添加:每个人可以选或者不选,总搜索数为2n,每次收缩需要O(1)的时间处理
    • 添加:重复的状态只需要计算一次,搜索空间为最大人数n*技能对应的状态压缩2m,总时间复杂度是O(n·2m)
  3. 预处理怎么考虑?(1)因为mask针对的是技能对应的索引,需要一个字典来存技能对应索引的情况;(2)再建立一个列表,遍历人,给出人对应技能索引的情况
  4. dfs时候的细节怎么考虑?
    • 参数一般是遍历情况和状态情况,这里是遍历到的索引i,满足情况mask
    • 退出情况是啥?i=n,需要区分mask的情况
      • (1) mask == (1<<n)-1, 返回True,[]
      • (2)mask != (1<<n)-1, False, []
    • 内部进行实现的dfs包括哪俩?
      • (1) 考虑第i个人的情况
      • (2)不考虑第i个人的情况
    • 根据第i+1个人的情况,有哪些处理方式?
      • (1)两个都返回False,返回False,[]
      • (2)加不行,不加行->返回 True,lst2
      • (3)加行,不加不行-> 返回True,lst1+[i]
      • (4)都行,看lst1+[i]和lst2的长度,那个短返回哪个

代码

class Solution:
def smallestSufficientTeam(self, req_skills: List[str], people: List[List[str]]) -> List[int]:
m = len(req_skills)
n = len(people)
skill_to_idx = dict()
# 建立技能对应m中索引的关系
for i, skill in enumerate(req_skills):
skill_to_idx[skill] = i
p_mask = [0]*n
# 建立人能满足的索引形式
for i, skills in enumerate(people):
mask = 0
for skill in skills:
mask |= (1<<skill_to_idx[skill])
p_mask[i] = mask
@cache
def dfs(i, mask):
if i == n:
if mask == (1<<m)-1:
return True, []
else:
return False, []
check1, lst1 = dfs(i+1, mask | p_mask[i])
check2, lst2 = dfs(i+1, mask)
if not check1 and not check2:
return False, []
if not check2:
return True, lst1+[i]
if not check1:
return True, lst2
else:
if len(lst1+[i]) < len(lst2):
return True, lst1 + [i]
else:
return True, lst2
return dfs(0, 0)[1]

复杂度

时间:O(n2m)
空间:待确定

总结

  1. 这里给出的是dfs+状态压缩的代码,后续可以追加dp+状态压缩做法
  2. dfs内需要判断取不取第i个人的情况
  3. dfs的返回结果写了2个参数,分别表示后续是否可行,结果列表
  4. 需要明确为啥考虑i时候,返回值需要lst1+[i]?lst1表示的是后面的最优结果吗?
posted @   zhangk1988  阅读(34)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示