【每日一题Day171】LC1125最小的必要团队 | 01背包 位运算
最小的必要团队【LC1125】
作为项目经理,你规划了一份需求的技能清单
req_skills
,并打算从备选人员名单people
中选出些人组成一个「必要团队」( 编号为i
的备选人员people[i]
含有一份该备选人员掌握的技能列表)。所谓「必要团队」,就是在这个团队中,对于所需求的技能列表
req_skills
中列出的每项技能,团队中至少有一名成员已经掌握。可以用每个人的编号来表示团队中的成员:
- 例如,团队
team = [0, 1, 3]
表示掌握技能分别为people[0]
,people[1]
,和people[3]
的备选人员。请你返回 任一 规模最小的必要团队,团队成员用人员编号表示。你可以按 任意顺序 返回答案,题目数据保证答案存在。
知道是01背包 状态压缩 但是代码写不出来
最近的每日一题还都挺复杂
-
思路
每位备选人员有选或者不选两种可能,而我们最终的目标是使找到具有所有技能的最少员工,该问题实质上为01背包问题。
-
物品为每个员工的技能,背包容量为所有需要的技能。【用状态压缩表示技能】
-
定义状态dp[j]dp[j]dp[j]表示 所有员工技能为jjj时需要的最少员工【用状态压缩表示员工】
-
-
一维动态规划
-
确定dp数组(dp table)以及下标的含义
dp[j]dp[j]dp[j]表示 所有员工技能为jjj时需要的最少员工
-
确定递推公式
对于每一个员工,若其具有的技能为
mask
,那么对于背包jjj而言-
不选员工iii:dp[j]=dp[j]dp[j] = dp[j]dp[j]=dp[j]
-
选员工iii:
除了员工iii所具有的技能,背包jjj还需要的技能为
mask & ~j
dp[j]=dp[mask&!j]∣(1<<i)dp[j]=dp[mask\\& !{j}] | (1 << i) dp[j]=dp[mask&!j]∣(1<<i)
取员工数目最少的结果,即二进制中1的个数最少的结果
-
-
dp数组如何初始化
最差情况时所有员工都取,因此dp[1:]dp[1:]dp[1:]初始化为(1>>m - 1),dp[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] 压缩成一个二进制数 maskmask |= 1 << sid.get(s);for (int j = 1; j < u; ++j) {long res = f[i][j]; // 不选 masklong res2 = f[i][j & ~mask] | (1L << i); // 选 maskf[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+m2n)O(T+m2^n)O(T+m2n),n为reqSkills长度,m为peopel的长度,T为people中字符串长度之和
-
空间复杂度:O(S+n2m)O(S+n2^m)O(S+n2m),S为reqSkills中字符串长度之和
-
-