【每日一题Day171】LC1125最小的必要团队 | 01背包 位运算

简介: 【每日一题Day171】LC1125最小的必要团队 | 01背包 位运算
最小的必要团队【LC1125】

作为项目经理,你规划了一份需求的技能清单 req_skills,并打算从备选人员名单 people 中选出些人组成一个「必要团队」( 编号为 i 的备选人员 people[i] 含有一份该备选人员掌握的技能列表)。

所谓「必要团队」,就是在这个团队中,对于所需求的技能列表 req_skills 中列出的每项技能,团队中至少有一名成员已经掌握。可以用每个人的编号来表示团队中的成员:

  • 例如,团队 team = [0, 1, 3] 表示掌握技能分别为 people[0]people[1],和 people[3] 的备选人员。

请你返回 任一 规模最小的必要团队,团队成员用人员编号表示。你可以按 任意顺序 返回答案,题目数据保证答案存在。


知道是01背包 状态压缩 但是代码写不出来

最近的每日一题还都挺复杂

  • 思路每位备选人员有选或者不选两种可能,而我们最终的目标是使找到具有所有技能的最少员工,该问题实质上为01背包问题。
  • 物品为每个员工的技能,背包容量为所有需要的技能。【用状态压缩表示技能】

image.png

4.确定遍历顺序
一维dp
先遍历物品,再从后往前遍历背包重量

5。举例推导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)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

image.png


目录
相关文章
|
2月前
|
算法
【每日一题Day363】LC275H 指数Ⅱ | 二分答案
【每日一题Day363】LC275H 指数Ⅱ | 二分答案
39 0
|
2月前
【每日一题Day297】LC1444切披萨的方案数 | 动态规划+二维前缀和
【每日一题Day297】LC1444切披萨的方案数 | 动态规划+二维前缀和
41 0
|
2月前
|
存储 人工智能 算法
【每日一题Day348】LC137只出现一次的数字Ⅱ | 状态转移
【每日一题Day348】LC137只出现一次的数字Ⅱ | 状态转移
29 0
|
2月前
【每日一题Day179】LC1157子数组中占绝大多数的元素 | 线段树
【每日一题Day179】LC1157子数组中占绝大多数的元素 | 线段树
30 0
|
2月前
【每日一题Day149】LC2389和有限的最长子序列 | 贪心+前缀和+二分查找
【每日一题Day149】LC2389和有限的最长子序列 | 贪心+前缀和+二分查找
27 0
|
2月前
|
C语言
浙大版《C语言程序设计(第3版)》题目集 练习8-2 计算两数的和与差 (10分)
浙大版《C语言程序设计(第3版)》题目集 练习8-2 计算两数的和与差 (10分)
|
2月前
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
36 1
【每日一题Day167】LC1000合并石头的最低成本 | 区间dp
|
2月前
【每日一题Day208】LC1335工作计划的最低难度 | 动态规划
【每日一题Day208】LC1335工作计划的最低难度 | 动态规划
31 0
|
2月前
【每日一题Day239】LC1494并行课程 II | 状态压缩 dp 位运算 子集
【每日一题Day239】LC1494并行课程 II | 状态压缩 dp 位运算 子集
30 0
|
2月前
【每日一题Day184】LC2413最小偶倍数 | 数学
【每日一题Day184】LC2413最小偶倍数 | 数学
19 0