2023-09-10:用go语言编写。作为项目经理,你规划了一份需求的技能清单 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]。

来自左程云

答案2023-09-10:

大体步骤如下:

1.首先,我们对 reqSkills 进行排序,获得排序后的技能列表。这是为了后续方便进行比较。例如,将 ["java", "nodejs", "reactjs"] 排序为 ["java", "nodejs", "reactjs"]。

2.初始化变量 n 为 reqSkills 的长度,变量 m 为 people 的长度,并创建一个长度为 m 的整数数组 statuses 用于记录每个人的技能状态。

3.对于每个人,我们通过比较技能列表和排序后的 reqSkills 列表,来确定他们掌握的技能状态。首先,将该人的技能列表排序。然后使用双指针法,一个指针指向排序后的 reqSkills 列表,另一个指针指向该人的技能列表。比较两个指针指向的技能,如果相等,则表示该人掌握了该技能,将对应的状态位置为1,并将两个指针都向后移动一位;如果 reqSkills[p1] 小于 skill[p2],则将指向 reqSkills 的指针向后移动一位;否则将指向技能列表的指针向后移动一位。重复这个过程直到其中一个指针超出范围。

4.将每个人的技能状态记录在 statuses 数组中。

5.创建一个二维数组 dp,其中 dp[i][j] 表示从第 i 个人开始,技能状态为 j 时,所需的最小团队人数。初始化 dp 数组的所有元素为 -1。

6.调用递归函数 process,该函数的参数包括:people 数组,技能列表的长度 n,当前处理的人员下标 i,当前的技能状态 status,以及 dp 数组。

7.在递归函数 process 中,首先判断当前技能状态是否已经满足所有需求,即 status 是否等于 (1<<n)-1。如果满足,则返回0表示不需要再增加人员。

8.接下来,判断是否已经遍历了所有人员,即 i 是否等于 people 数组的长度。如果是,说明无法满足所有需求,并返回一个较大的值,这里使用 1<<31-1 来表示无穷大。

9.然后,判断 dp 数组中是否已经记录了当前人员和技能状态的最小团队人数,如果是,直接返回该值。

10.在递归函数中,我们有两个递归调用,第一个是继续尝试从下一个人员开始不增加人员的情况,即调用 process(people, n, i+1, status, dp),将返回的值保存在变量 p1 中。

11.第二个递归调用是尝试从下一个人员开始增加当前人员的情况,即调用 process(people, n, i+1, status|people[i], dp),将返回的值保存在变量 p2 中。注意,这里的参数 status|people[i] 表示将当前人员的技能状态添加到当前技能状态中。

12.如果 p2 不等于 1<<31-1,说明可以满足当前需求,将 p2+1 指代的团队人数保存在变量 ans 中,否则将 ans 设置为 p1。

13.将 ans 保存在 dp 数组中以便下次使用,并返回 ans。

14.在主函数中,根据返回的最小团队人数 size,创建一个大小为 size 的整数数组 ans 和一个指示 ans 数组下标的变量 ansi。

15.初始化变量 i 为0,status 为0,用于记录当前处理的人员下标和技能状态。

16.如果 status 不等于 (1<<n)-1,即还没有满足所有需求,执行循环。在循环中,判断两个条件:如果 i+1 等于 m,说明已经遍历到了最后一个人员;如果 dp[i][status] 不等于 dp[i+1][status],表示从当前人员开始增加人员可以满足当前需求。

17.如果满足上述两个条件之一,将 i 添加到 ans 数组中,并将 ansi 自增1。然后将当前人员的技能状态添加到当前技能状态中。

18.无论是否满足条件,将 i 自增1。

19.执行完循环后,返回 ans 数组作为结果。

总的时间复杂度为O(m * (2^n)),额外空间复杂度为O(m * (2^n))。

go完整代码如下:

package main

import (
"fmt"
"sort"
) func smallestSufficientTeam(reqSkills []string, people [][]string) []int {
sort.Strings(reqSkills)
n := len(reqSkills)
m := len(people)
statuses := make([]int, m)
for i := 0; i < m; i++ {
skillStatus := 0
skill := people[i]
sort.Strings(skill)
p1, p2 := 0, 0
for p1 < n && p2 < len(skill) {
compare := reqSkills[p1] == skill[p2]
if compare {
skillStatus |= 1 << p1
p1++
p2++
} else if reqSkills[p1] < skill[p2] {
p1++
} else {
p2++
}
}
statuses[i] = skillStatus
} dp := make([][]int, m)
for i := 0; i < m; i++ {
dp[i] = make([]int, 1<<n)
for j := 0; j < 1<<n; j++ {
dp[i][j] = -1
}
} size := process(statuses, n, 0, 0, dp)
ans := make([]int, size)
ansi := 0
i := 0
status := 0
for status != (1<<n)-1 {
if i+1 == m || dp[i][status] != dp[i+1][status] {
ans[ansi] = i
ansi++
status |= statuses[i]
}
i++
}
return ans
} func process(people []int, n, i, status int, dp [][]int) int {
if status == (1<<n)-1 {
return 0
}
if i == len(people) {
return 1<<31 - 1
}
if dp[i][status] != -1 {
return dp[i][status]
}
p1 := process(people, n, i+1, status, dp)
p2 := 1<<31 - 1
next2 := process(people, n, i+1, status|people[i], dp)
if next2 != 1<<31-1 {
p2 = 1 + next2
}
ans := min(p1, p2)
dp[i][status] = ans
return ans
} func min(a, b int) int {
if a < b {
return a
}
return b
} func main() {
reqSkills := []string{"java", "nodejs", "reactjs"}
people := [][]string{{"java"}, {"nodejs"}, {"nodejs", "reactjs"}} result := smallestSufficientTeam(reqSkills, people)
fmt.Println(result)
}

rust完整代码如下:

fn smallest_sufficient_team(req_skills: Vec<String>, people: Vec<Vec<String>>) -> Vec<i32> {
let n = req_skills.len();
let m = people.len();
let mut statuses = vec![0; m];
for (i, skill) in people.iter().enumerate() {
let mut skill_status = 0;
let mut sorted_skill = skill.clone();
sorted_skill.sort();
let mut p1 = 0;
let mut p2 = 0;
while p1 < n && p2 < sorted_skill.len() {
match req_skills[p1].cmp(&sorted_skill[p2]) {
std::cmp::Ordering::Less => p1 += 1,
std::cmp::Ordering::Greater => p2 += 1,
std::cmp::Ordering::Equal => {
skill_status |= 1 << p1;
p1 += 1;
p2 += 1;
}
}
}
statuses[i] = skill_status;
} let mut dp = vec![vec![-1; 1 << n]; m];
let size = process(&statuses, n, 0, 0, &mut dp);
let mut ans = vec![0; size as usize];
let mut ansi = 0;
let mut i = 0;
let mut status: i32 = 0; while status != (1 << n) - 1 {
if i + 1 == m || dp[i][status as usize] != dp[i + 1][status as usize] {
ans[ansi] = i as i32;
ansi += 1;
status |= statuses[i as usize];
}
i += 1;
} ans
} fn process(people: &[i32], n: usize, i: usize, status: i32, dp: &mut Vec<Vec<i32>>) -> i32 {
if status == (1 << n) - 1 {
return 0;
} if i == people.len() {
return i32::MAX;
} if dp[i][status as usize] != -1 {
return dp[i][status as usize];
} let p1 = process(people, n, i + 1, status, dp);
let mut p2 = i32::MAX;
let next2 = process(people, n, i + 1, status | people[i], dp);
if next2 != i32::MAX {
p2 = 1 + next2;
} let ans = p1.min(p2);
dp[i][status as usize] = ans;
ans
} fn main() {
let req_skills = vec![
"java".to_string(),
"nodejs".to_string(),
"reactjs".to_string(),
];
let people = vec![
vec!["java".to_string()],
vec!["nodejs".to_string()],
vec!["nodejs".to_string(), "reactjs".to_string()],
];
let result = smallest_sufficient_team(req_skills, people);
println!("{:?}", result);
}

c++完整代码如下:

#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <cmath> using namespace std; int process(const vector<int>& people, int n, int i, int status, unordered_map<int, int>& dp) {
if (status == (1 << n) - 1) {
return 0;
}
if (i == people.size()) {
return INT_MAX;
}
int key = (i << n) | status;
if (dp.find(key) != dp.end()) {
return dp[key];
}
int p1 = process(people, n, i + 1, status, dp);
int p2 = INT_MAX;
int next2 = process(people, n, i + 1, status | people[i], dp);
if (next2 != INT_MAX) {
p2 = 1 + next2;
}
int ans = min(p1, p2);
dp[key] = ans;
return ans;
} vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
unordered_map<string, int> skillMap;
int count = 0;
for (const string& skill : req_skills) {
skillMap[skill] = count++;
}
int n = count;
int m = people.size();
vector<int> statuses(m);
for (int i = 0; i < m; i++) {
int skillStatus = 0;
const vector<string>& skills = people[i];
for (const string& skill : skills) {
skillStatus |= 1 << skillMap[skill];
}
statuses[i] = skillStatus;
}
unordered_map<int, int> dp;
int size = process(statuses, n, 0, 0, dp);
vector<int> ans;
int i = 0, status = 0;
while (status != (1 << n) - 1) {
if (i + 1 == m || dp[i << n | status] != dp[(i + 1) << n | status]) {
ans.push_back(i);
status |= statuses[i];
}
i++;
}
return ans;
} int main() {
vector<string> req_skills = { "java", "nodejs", "reactjs" };
vector<vector<string>> people = { {"java"}, {"nodejs"}, {"nodejs", "reactjs"} }; vector<int> team = smallestSufficientTeam(req_skills, people);
cout << "Team members: ";
for (int member : team) {
cout << member << " ";
}
cout << endl; return 0;
}

c完整代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h> typedef struct {
int* data;
int size;
int capacity;
} IntArray; IntArray* createIntArray() {
IntArray* arr = (IntArray*)malloc(sizeof(IntArray));
arr->data = NULL;
arr->size = 0;
arr->capacity = 0;
return arr;
} void append(IntArray* arr, int value) {
if (arr->size >= arr->capacity) {
int newCapacity = arr->capacity == 0 ? 1 : arr->capacity * 2;
int* newData = (int*)malloc(sizeof(int) * newCapacity);
if (arr->data != NULL) {
memcpy(newData, arr->data, sizeof(int) * arr->size);
free(arr->data);
}
arr->data = newData;
arr->capacity = newCapacity;
}
arr->data[arr->size++] = value;
} void destroyIntArray(IntArray* arr) {
if (arr != NULL) {
if (arr->data != NULL) {
free(arr->data);
}
free(arr);
}
} int findSkillIndex(char** skills, int skillsSize, char* target) {
for (int i = 0; i < skillsSize; i++) {
if (strcmp(skills[i], target) == 0) {
return i;
}
}
return -1;
} void smallestSufficientTeam(char** req_skills, int req_skillsSize, char*** people, int peopleSize, int* peopleColSize, int* returnSize, int** returnArray) {
char** skills = (char**)malloc(sizeof(char*) * req_skillsSize);
for (int i = 0; i < req_skillsSize; i++) {
skills[i] = _strdup(req_skills[i]);
} int n = req_skillsSize;
int m = peopleSize;
int* statuses = (int*)malloc(sizeof(int) * m); for (int i = 0; i < m; i++) {
int skillStatus = 0;
for (int j = 0; j < peopleColSize[i]; j++) {
int skillIndex = findSkillIndex(skills, req_skillsSize, people[i][j]);
if (skillIndex != -1) {
skillStatus |= 1 << skillIndex;
}
}
statuses[i] = skillStatus;
} int** dp = (int**)malloc(sizeof(int*) * m);
for (int i = 0; i < m; i++) {
dp[i] = (int*)malloc(sizeof(int) * (1 << n));
for (int j = 0; j < (1 << n); j++) {
dp[i][j] = -1;
}
} int size = process(statuses, n, 0, 0, dp); *returnSize = size;
*returnArray = (int*)malloc(sizeof(int) * size);
int index = 0;
int i = 0;
int status = 0; while (status != (1 << n) - 1) {
if (i + 1 == m || dp[i][status] != dp[i + 1][status]) {
(*returnArray)[index++] = i;
status |= statuses[i];
}
i++;
} for (int i = 0; i < m; i++) {
free(dp[i]);
}
free(dp); for (int i = 0; i < req_skillsSize; i++) {
free(skills[i]);
}
free(skills);
free(statuses);
} int process(int* people, int n, int i, int status, int** dp) {
if (status == (1 << n) - 1) {
return 0;
}
if (i == n) {
return INT_MAX;
}
if (dp[i][status] != -1) {
return dp[i][status];
} int p1 = process(people, n, i + 1, status, dp); int p2 = INT_MAX;
int next2 = process(people, n, i + 1, status | people[i], dp);
if (next2 != INT_MAX) {
p2 = 1 + next2;
} int ans = p1 < p2 ? p1 : p2;
dp[i][status] = ans;
return ans;
} int main() {
char* req_skills[] = { "java", "nodejs", "reactjs" };
int req_skillsSize = sizeof(req_skills) / sizeof(req_skills[0]); char** people[] = {
(char* []) {
"java"
},
(char* []) {
"nodejs"
},
(char* []) {
"nodejs", "reactjs"
}
};
int peopleSize = sizeof(people) / sizeof(people[0]);
int peopleColSize[] = { 1, 1, 2 }; int returnSize;
int* returnArray; smallestSufficientTeam(req_skills, req_skillsSize, people, peopleSize, peopleColSize, &returnSize, &returnArray); printf("Smallest Sufficient Team:\n");
for (int i = 0; i < returnSize; i++) {
printf("%d ", returnArray[i]);
}
printf("\n"); free(returnArray); return 0;
}

2023-09-10:用go语言编写。作为项目经理,你规划了一份需求的技能清单 req_skills, 并打算从备选人员名单 people 中选出些人组成一个「必要团队」 ( 编号为 i 的备选人员的更多相关文章

  1. Linux在shell中进入python敲方向键出现「^[[C^[[D」的解决办法

    安装yum -y install readline-devel,然后在重新编译python

  2. 【转】具透 | 你可能不知道,iOS 10 有一个中国「特供」的联网权限功能

    9 月底,苹果正式在北京成立了苹果中国研发中心.近几年,我们也在每年更新的 iOS 系统中不断看到,苹果对中国市场的关照.从早前的九宫格输入法,到最近的骚扰电话拦截,都照顾了国内用户的需求. 在 iO ...

  3. 「前端开发者」如何把握住「微信小程序」这波红利?

    由于前两周一直在老家处理重要事情,虽然朋友圈被「微信小程序」刷爆了,但并没有时间深入了解. 昨天回广州之后,第一件事情就是把「微信小程序」相关的文章.开发文档.设计规范全部看了一遍,基本上明白了「微信 ...

  4. Mditor 发布「桌面版」了 - http://mditor.com

    简单说明 Mditor 最早只有「组件版」,随着「桌面版」的发布,Mditor 目前有两个版本: 可嵌入到任意 Web 应用的 Embed 版本,这是一桌面版的基础,Repo: https://git ...

  5. 微服务架构之「 API网关 」

    在微服务架构的系列文章中,前面已经通过文章<架构设计之「服务注册 」>介绍过了服务注册的原理和应用,今天这篇文章我们来聊一聊「 API网关 」. 「 API网关 」是任何微服务架构的重要组 ...

  6. 基于 Node.js 的轻量「持续集成」工具 CIZE

    CIZE 是什么? CIZE 是一个「持续集成」工具,希望能让开发人员更快捷的搭建一个完整.可靠.便捷的 CI 服务. 甚至可以像 Gulp 或 Grunt 一样,仅仅通过一个 cizefile.js ...

  7. 分享开源 Markdown 编辑器 Mditor 的「桌面版」

    简单说明 Mditor 最早只有「组件版」,随着「桌面版」的发布,Mditor 目前有两个版本: 可嵌入到任意 Web 应用的 Embed 版本,这是一桌面版的基础,Repo: https://git ...

  8. ERNIE:知识图谱结合BERT才是「有文化」的语言模型

    自然语言表征模型最近受到非常多的关注,很多研究者将其视为 NLP 最重要的研究方向之一.例如在大规模语料库上预训练的 BERT,它可以从纯文本中很好地捕捉丰富的语义模式,经过微调后可以持续改善不同 N ...

  9. 转载_最值得阅读学习的10个C语言开源项目代码

    "源代码面前,了无秘密",阅读优秀代码无疑是开发人员得以窥见软件堂奥而登堂入室的捷径.本文选取10个C语言优秀开源项目的代码作为范本,分别给予点评,免去东搜西罗之苦,点赞!那么问题 ...

  10. Windows 10 如何使用「系统还原」功能备份系统状态和配置

    https://www.sysgeek.cn/windows-10-system-restore/ 在 Windows 10 系统中,「系统还原」功能旨在创建配置快照,并在检测到系统更改时将其工作状态 ...

随机推荐

  1. Debian12安装.NET7 SDK

    Debian,作为最受欢迎的 Linux 发行版之一,于 2023 年 6 月 10 日正式发布了其最新版本 Debian 12,代号"Bookworm".Debian 12 带来 ...

  2. 再学Blazor——概述

    简介 Blazor 是一种 .NET 前端 Web 框架,同时支持服务器端呈现和客户端交互性. 使用 C# 语言创建丰富的交互式 UI 共享前后端应用逻辑 可以生成混合桌面和移动应用 受益于 .NET ...

  3. 2.MongoDB Sharding Cluster分片集群

    分片集群-规划 10个实例:38017-38026 (1)configserver:38018-38020 3台构成的复制集(1主两从,不支持arbiter)38018-38020(复制集名字conf ...

  4. QSplitter 自我总结

    ①.QSplitter(QWidget* parent = Q_NULLPTR); //构造函数 QSplitter(Qt::Orientation orientation , QWidget* pa ...

  5. .net core 到底行不行!超高稳定性和性能的客服系统:性能实测

    业余时间用 .net core 写了一个升讯威在线客服系统.并在博客园写了一个系列的文章,介绍了这个开发过程. 我把这款业余时间写的小系统丢在网上,陆续有人找我要私有化版本,我都给了,毕竟软件业的初衷 ...

  6. Redis系列之常见数据类型应用场景

    目录 String 简单介绍 常见命令 应用场景 Hash 简单介绍 常见命令 应用场景 List 简单介绍 常见命令 应用场景 Set 简单介绍 常见命令 应用场景 Sorted Set(Zset) ...

  7. bad_python

    对着正确的pyc文件在010把题目文件的前缀改掉,然后在线反编译得到代码

  8. HDL刷题:Count clock

    原题链接 要写一个12小时的时钟. 由题目得知,reset信号的优先级最高,其次是enable,这里很好实现. 我的思路: 写了一个4位的bcd计数器,并实例化了4个,对ss与mm的[7:4]与[3: ...

  9. L2-033 简单计算器

    #include <bits/stdc++.h> using namespace std; int cal(int a, int b, char c) { int t; if (c == ...

  10. Educational Codeforces Round 102 (Rated for Div. 2) A~D题

    写在前边 链接:Educational Codeforces Round 102 (Rated for Div. 2) 第一场打CF,过了AB两题,不过速度挺慢,C题属实没看懂,D题写了个常规做法之后 ...