作为项目经理,你规划了一份需求的技能清单 req_skills,并打算从备选人员名单 people 中选出些人组成一个「必要团队」( 编号为 i 的备选人员 people[i] 含有一份该备选人员掌握的技能列表)。
所谓「必要团队」,就是在这个团队中,对于所需求的技能列表 req_skills 中列出的每项技能,团队中至少有一名成员已经掌握。
我们可以用每个人的编号来表示团队中的成员:例如,团队 team = [0, 1, 3] 表示掌握技能分别为 people[0],people[1],和 people[3] 的备选人员。
请你返回 任一 规模最小的必要团队,团队成员用人员编号表示。你可以按任意顺序返回答案,本题保证答案存在。
输入:req_skills = ["java","nodejs","reactjs"], people = [["java"],["nodejs"],["nodejs","reactjs"]]
输出:[0,2]
输入:req_skills = ["algorithms","math","java","reactjs","csharp","aws"], people = [["algorithms","math","java"],["algorithms","math","reactjs"],["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]]
输出:[1,2]
思路:dp加二进制表示技能种类。
1、二进制表示技能:题目的技能数目<=16,完全可以用1,表示第一种技能,10表示第二种技能,100表示第三种技能,,以此类推 int完全可以容纳。进而我们可以用一个数字来表示当前拥有的技能总数,像5=4+1,就是拥有了技能1和技能3。1<<skNum -1就是表示拥有了所有的技能。以此来创建动态规划的数组。
2、动态规划:我们遍历每个人的技能,根据每个人的技能去更新dp的值。
状态:dp[state] 表示掌握技能的状态为state时,需要的最少人数。根据上面的举例:dp[0] =1 ; dp[1] = 1; dp[3] = 2;
list[state] 表示这个状态下 人员的编号。
转移方程: dp[nextState] = min(dp[nextState],dp[ preState | p[i] ] + 1 ) ; (p[i] 是第i个人掌握技能的状态,preState | p[i] == dp[nextState] ) ;
结果要覆盖所有的技能,那么我们要求的状态就是 (1<<(skill_num)-1) ,所以最少的人数就是dp[1<<(skill_num) -1];
结果就是list[ ( 1<<skill_num ) - 1] ,人员编号的状态 随着dp的转移而转移。
代码如下:
public int[] smallestSufficientTeam(String[] req_skills, List<List<String>> people) {
int pNum = people.size();
int skNum = req_skills.length;
int[] dp = new int[1<<skNum];
List<Integer>[] res = new ArrayList[1<<skNum];
Map<String,Integer> map = new HashMap<>();
for(int i=0;i<skNum;i++){
map.put(req_skills[i],1<<i);
}
for(int i=0;i<(1<<skNum);i++){
dp[i]=-1;
res[i] = new ArrayList<>();
}
dp[0]=0;
for(int i=0;i<pNum;i++){
int sk=0;
for(String str:people.get(i))
sk|=( map.get(str) == null ? 0 : map.get(str) );//获取当前人的技能类
for(int st=0;st<(1<<skNum);st++){
if(dp[st]==-1) continue;
int newState = sk|st;
if(dp[newState]==-1||dp[st]+1<dp[newState]){
dp[newState] = dp[st] + 1; //更新人员数量
res[newState].clear();
res[newState].addAll(res[st]); //更新人员的编号
res[newState].add(i);
}
}
}
int[] result = new int[res[(1<<skNum)-1].size()];
for(int i=0;i<result.length;i++){
result[i] = res[(1<<skNum)-1].get(i);
}
return result;
}
运行结果如下:
希望可以帮到大家,有不懂的地方可以提问。