最小的必要团队【LC1125】
作为项目经理,你规划了一份需求的技能清单
req_skills
,并打算从备选人员名单people
中选出些人组成一个「必要团队」( 编号为i
的备选人员people[i]
含有一份该备选人员掌握的技能列表)。所谓「必要团队」,就是在这个团队中,对于所需求的技能列表
req_skills
中列出的每项技能,团队中至少有一名成员已经掌握。可以用每个人的编号来表示团队中的成员:
- 例如,团队
team = [0, 1, 3]
表示掌握技能分别为people[0]
,people[1]
,和people[3]
的备选人员。请你返回 任一 规模最小的必要团队,团队成员用人员编号表示。你可以按 任意顺序 返回答案,题目数据保证答案存在。
知道是01背包 状态压缩 但是代码写不出来
最近的每日一题还都挺复杂
-
思路
每位备选人员有选或者不选两种可能,而我们最终的目标是使找到具有所有技能的最少员工,该问题实质上为01背包问题。
-
物品为每个员工的技能,背包容量为所有需要的技能。【用状态压缩表示技能】
-
定义状态 d p [ j ] dp[j] dp[j]表示 所有员工技能为 j j j时需要的最少员工【用状态压缩表示员工】
-
-
一维动态规划
-
确定dp数组(dp table)以及下标的含义
d p [ j ] dp[j] dp[j]表示 所有员工技能为 j j j时需要的最少员工
-
确定递推公式
对于每一个员工,若其具有的技能为
mask
,那么对于背包 j j j而言-
不选员工 i i i: d p [ j ] = d p [ j ] dp[j] = dp[j] dp[j]=dp[j]
-
选员工 i i i:
除了员工 i i i所具有的技能,背包 j j j还需要的技能为
mask & ~j
d p [ j ] = d p [ m a s k & ! j ] ∣ ( 1 < < i ) dp[j]=dp[mask\& !{j}] | (1 << i) dp[j]=dp[mask&!j]∣(1<<i)
取员工数目最少的结果,即二进制中1的个数最少的结果
-
-
dp数组如何初始化
最差情况时所有员工都取,因此 d p [ 1 : ] dp[1:] dp[1:]初始化为(1>>m - 1), d p [ 0 ] dp[0] dp[0]初始化为0
-
确定遍历顺序
一维dp
先遍历物品,再从后往前遍历背包重量
-
举例推导dp数组
class Solution { public int[] smallestSufficientTeam(String[] reqSkills, List<List<String>> people) { var sid = new HashMap<String, Integer>(); int m = reqSkills.length; for (int i = 0; i < m; ++i) sid.put(reqSkills[i], i); // 字符串映射到下标 int n = people.size(), u = 1 << m; // f[i+1][j] 表示从前 i 个集合中选择一些集合,并集等于 j,需要选择的最小集合 var f = new long[n + 1][u]; Arrays.fill(f[0], (1L << n) - 1); // 对应记忆化搜索中的 if (i < 0) return all; f[0][0] = 0; for (int i = 0; i < n; ++i) { int mask = 0; for (var s : people.get(i)) // 把 people[i] 压缩成一个二进制数 mask mask |= 1 << sid.get(s); for (int j = 1; j < u; ++j) { long res = f[i][j]; // 不选 mask long res2 = f[i][j & ~mask] | (1L << i); // 选 mask f[i + 1][j] = Long.bitCount(res) < Long.bitCount(res2) ? res : res2; } } long res = f[n][u - 1]; var ans = new int[Long.bitCount(res)]; for (int i = 0, j = 0; i < n; ++i) if (((res >> i) & 1) > 0) ans[j++] = i; // 所有在 res 中的下标 return ans; } } 作者:灵茶山艾府 链接:https://leetcode.cn/problems/smallest-sufficient-team/solutions/2214387/zhuang-ya-0-1-bei-bao-cha-biao-fa-vs-shu-qode/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
-
复杂度
-
时间复杂度: O ( T + m 2 n ) O(T+m2^n) O(T+m2n),n为reqSkills长度,m为peopel的长度,T为people中字符串长度之和
-
空间复杂度: O ( S + n 2 m ) O(S+n2^m) O(S+n2m),S为reqSkills中字符串长度之和
-
-