In a project, you have a list of required skills req_skills, and a list of people. The ith person people[i] contains a list of skills that the person has.
Consider a sufficient team: a set of people such that for every required skill in req_skills, there is at least one person in the team who has that skill. We can represent these teams by the index of each person.
team = [0, 1, 3] represents the people with skills people[0], people[1], and people[3].Return any sufficient team of the smallest possible size, represented by the index of each person. You may return the answer in any order.
It is guaranteed an answer exists.
Example 1:
Input: req_skills = ["java","nodejs","reactjs"], people = [["java"],["nodejs"],["nodejs","reactjs"]] Output: [0,2]
Example 2:
Input: req_skills = ["algorithms","math","java","reactjs","csharp","aws"], people = [["algorithms","math","java"],["algorithms","math","reactjs"],["java","csharp","aws"],["reactjs","csharp"],["csharp","math"],["aws","java"]] Output: [1,2]
Constraints:
1 <= req_skills.length <= 161 <= req_skills[i].length <= 16req_skills[i] consists of lowercase English letters.req_skills are unique.1 <= people.length <= 600 <= people[i].length <= 161 <= people[i][j].length <= 16people[i][j] consists of lowercase English letters.people[i] are unique.people[i] is a skill in req_skills.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to finding the smallest team that knows all required skills involves checking every possible combination of people. We start by trying small teams and gradually increase the team size, verifying if each team has all the necessary skills.
Here's how the algorithm would work step-by-step:
def smallest_sufficient_team_brute_force(required_skills, people):
number_of_required_skills = len(required_skills)
number_of_people = len(people)
skill_to_index = {skill: index for index, skill in enumerate(required_skills)}
people_masks = []
for person_skills in people:
person_mask = 0
for skill in person_skills:
person_mask |= 1 << skill_to_index[skill]
people_masks.append(person_mask)
for team_size in range(1, number_of_people + 1):
# Iterate through possible team sizes, starting from 1.
for combination in get_combinations(number_of_people, team_size):
team_mask = 0
# Calculate the bitmask representing the skills of the current team.
for person_index in combination:
team_mask |= people_masks[person_index]
# Check if the current team has all the required skills.
if team_mask == (1 << number_of_required_skills) - 1:
return list(combination)
return list(range(number_of_people))
def get_combinations(number_of_people, team_size):
if team_size == 0:
yield ()
return
if team_size > number_of_people:
return
for index in range(number_of_people):
remaining_number_of_people = number_of_people - (index + 1)
for sub_combination in get_combinations(index + 1, team_size - 1):
yield (index,) + sub_combinationThis problem is about finding the smallest group of people who collectively know all the required skills. The most efficient way to solve it is by using a clever method that breaks the problem down into smaller, manageable pieces and remembers the best solutions found so far.
Here's how the algorithm would work step-by-step:
def smallest_sufficient_team(required_skills, people_skills):
number_of_required_skills = len(required_skills)
skill_to_index = {skill: i for i, skill in enumerate(required_skills)}
number_of_people = len(people_skills)
skill_sets = []
for person_skills in people_skills:
skill_set_mask = 0
for skill in person_skills:
if skill in skill_to_index:
skill_set_mask |= 1 << skill_to_index[skill]
skill_sets.append(skill_set_mask)
# dp[skill_mask] is the smallest team that covers the skills in skill_mask
dp = {0: []}
# Iterate through each person to update the smallest team required.
for person_index, skill_set_mask in enumerate(skill_sets):
for current_skill_mask, current_team in list(dp.items()):
combined_skill_mask = current_skill_mask | skill_set_mask
# Only proceed if the combined skill set is new or smaller.
if combined_skill_mask not in dp or len(dp[combined_skill_mask]) > len(current_team) + 1:
# Update the smallest team with the current person included.
dp[combined_skill_mask] = current_team + [person_index]
# The smallest team to cover all skills is dp[(1 << number_of_required_skills) - 1]
return dp[(1 << number_of_required_skills) - 1]| Case | How to Handle |
|---|---|
| Empty skills array | Return an empty team array if the required skills array is empty as no one is needed. |
| Empty people array | Return an empty team array if there are no people since no team can be formed. |
| No one has the required skills | Return null or an appropriate indicator that a valid team cannot be formed. |
| Single person has all required skills | Return an array containing only that person's index as the smallest sufficient team. |
| Large number of people and skills (scalability) | Optimize the bitmasking or dynamic programming approach to ensure efficient computation within time and memory limits. |
| Skills are duplicates within the required skills list | Deduplicate the skills to ensure correct bitmasking and prevent incorrect matching. |
| People have duplicate skills | The algorithm should handle duplicate skills without issue, as it checks for presence of all required skills overall, not skill uniqueness per person. |
| Multiple possible smallest sufficient teams | Return any one of the valid smallest sufficient teams, as the problem statement does not specify a preference. |