2023-04-08每日一题
一、题目编号
1125. 最小的必要团队
二、题目链接
https://leetcode.cn/problems/smallest-sufficient-team/
三、题目描述
作为项目经理,你规划了一份需求的技能清单 req_skills,并打算从备选人员名单 people 中选出些人组成一个「必要团队」( 编号为 i 的备选人员 people[i] 含有一份该备选人员掌握的技能列表)。
所谓「必要团队」,就是在这个团队中,对于所需求的技能列表 req_skills 中列出的每项技能,团队中至少有一名成员已经掌握。可以用每个人的编号来表示团队中的成员:
例如,团队 team = [0, 1, 3] 表示掌握技能分别为 people[0],people[1],和 people[3] 的备选人员。
请你返回 任一 规模最小的必要团队,团队成员用人员编号表示。你可以按 任意顺序 返回答案,题目数据保证答案存在。
四、解题代码
class Solution {
unordered_map<string, int> index;
public:
vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
int n = req_skills.size();
int m = people.size();
for(int i = 0; i < n; ++i){
index[ req_skills[i] ] = i;
}
vector<vector<int>> dp(1 << n);
for(int i = 0; i < m; ++i){
int cur_skill = 0;
for(int j = 0; j < people[i].size(); ++j){
cur_skill |= (1 << index[people[i][j]]);
}
for(int prev = 0; prev < (1 << n); ++prev){
if(prev > 0 && dp[prev].size() == 0){
continue;
}
int comb = prev | cur_skill;
if(comb == prev){
continue;
}
if(dp[comb].size() == 0 || dp[prev].size() + 1 < dp[comb].size()) {
dp[comb] = dp[prev];
dp[comb].push_back(i);
}
}
}
return dp[(1 << n) - 1];
}
};
五、解题思路
(1)首先我们将每一个技能所对应的数组标号用哈希表进行标记起来。我们用2进制数字来表示技能,比如一个技能java在数组中位置是0,则1<<0则代表具备该技能。
(2)我们用一个包含1 << n的长度的二维数组,来分别存储不同情况下的最小人员。
(3)接下来运用动态规划,依次遍历每一个成员,并从0 ~ (1<<n)- 1做为前置情况prev,来更新dp数组。首先用cur_skill通过位运算来计算该成员所拥有的技能用二进制数如何表示。如果prev>0(表示已经修行了技能)并且dp[prev].size() == 0(表示此时并不存在满足prev情况的人员分配),则跳过该情况判断。接下来取prev 和 cur_skill的并集 comb,如果comb与prev相同,则表示该人员对于prev是多余人员,直接跳过剩下的判断。之后判断,如果没有comb情况下的人员分配,则更新该人员分配,如果新的人员分配少于旧的人员分配,则更新人员分配。
(4)最后返回全技能拥有的人员分配。