1125.最小的必要团队

题目描述

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

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

基本分析

  1. 技能的数量最大为16,暗示什么?可以用一个长度不超过16的二进制数表示每个技能是不是已经有人掌握
  2. 不添加记忆化和添加记忆化在搜索上的区别在哪?
    • 不添加:每个人可以选或者不选,总搜索数为\(2^n\),每次收缩需要O(1)的时间处理
    • 添加:重复的状态只需要计算一次,搜索空间为最大人数n*技能对应的状态压缩\(2^m\),总时间复杂度是\(O(n·2^m)\)
  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(n*2{m})\)
空间:待确定

总结

  1. 这里给出的是dfs+状态压缩的代码,后续可以追加dp+状态压缩做法
  2. dfs内需要判断取不取第i个人的情况
  3. dfs的返回结果写了2个参数,分别表示后续是否可行,结果列表
  4. 需要明确为啥考虑i时候,返回值需要lst1+[i]?lst1表示的是后面的最优结果吗?
posted @ 2022-10-20 11:42  zhangk1988  阅读(39)  评论(0)    收藏  举报