Skip to content

Commit 0cffe5d

Browse files
committed
feat: add solutions to lc problem: No.1125
No.1125.Smallest Sufficient Team
1 parent 9e4b3ce commit 0cffe5d

File tree

7 files changed

+531
-175
lines changed

7 files changed

+531
-175
lines changed

solution/1100-1199/1125.Smallest Sufficient Team/README.md

+192-57
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,23 @@
5454

5555
<!-- 这里可写通用的实现逻辑 -->
5656

57-
**方法一:状态压缩 + 记忆化搜索**
57+
**方法一:状态压缩动态规划**
58+
59+
我们注意到,技能清单 `req_skills` 的长度不超过 $16$,因此,我们可以用一个长度不超过 $16$ 的二进制数来表示每一种技能是否被掌握。不妨记数组 `req_skills` 的长度为 $m$,数组 `people` 的长度为 $n$。
60+
61+
我们先将 `req_skills` 中的每个技能映射到一个编号,即 $d[s]$ 表示技能 $s$ 的编号。然后,我们遍历 `people` 中的每个人,将其掌握的技能用二进制数表示,即 $p[i]$ 表示编号为 $i$ 的人掌握的技能。
62+
63+
接下来,我们定义以下三个数组,其中:
64+
65+
- 数组 $f[i]$ 表示掌握技能集合为 $i$ 的最少人数,其中 $i$ 的二进制表示中的每一位为 $1$ 的位置,表示对应的技能被掌握。初始时 $f[0] = 0$,其余位置均为无穷大。
66+
- 数组 $g[i]$ 表示掌握技能集合为 $i$ 的最少人数时,最后一个人的编号。
67+
- 数组 $h[i]$ 表示掌握技能集合为 $i$ 的最少人数时,上一个技能集合状态。
68+
69+
我们在 $[0,..2^m-1]$ 的范围内枚举每个技能集合,对于每个技能集合 $i$,我们枚举 `people` 中的每个人,如果 $f[i] + 1 \lt f[i | p[j]]$,说明 $f[i | p[j]]$ 可以通过 $f[i]$ 转移得到,此时,我们更新 $f[i | p[j]]$ 为 $f[i] + 1$,并将 $g[i | p[j]]$ 更新为 $j$,同时将 $h[i | p[j]]$ 更新为 $i$。即当前技能集合状态为 $i | p[j]$ 时,最后一个人的编号为 $j$,上一个技能集合状态为 $i$。这里符号 $|$ 表示按位或运算。
70+
71+
最后,我们从技能集合 $i=2^m-1$ 开始,找到此时最后一个人的编号 $g[i]$,将其加入答案中,然后将 $i$ 更新为 $h[i]$,不断地向前回溯,直到 $i=0$,即可得到最小的必要团队中的人员编号。
72+
73+
时间复杂度 $O(2^m \times n)$,空间复杂度 $O(2^m)$。其中 $m$ 和 $n$ 分别为 `req_skills``people` 的长度。
5874

5975
<!-- tabs:start -->
6076

@@ -64,29 +80,33 @@
6480

6581
```python
6682
class Solution:
67-
def smallestSufficientTeam(self, req_skills: List[str], people: List[List[str]]) -> List[int]:
68-
@cache
69-
def dfs(i, state):
70-
if i == n:
71-
return [] if state == (1 << m) - 1 else None
72-
ans1 = dfs(i + 1, state)
73-
ans2 = dfs(i + 1, state | ps[i])
74-
if ans1 is None and ans2 is None:
75-
return None
76-
if ans1 is None:
77-
return [i] + ans2
78-
if ans2 is None:
79-
return ans1
80-
return min(ans1, [i] + ans2, key=len)
81-
83+
def smallestSufficientTeam(
84+
self, req_skills: List[str], people: List[List[str]]
85+
) -> List[int]:
8286
d = {s: i for i, s in enumerate(req_skills)}
83-
m = len(req_skills)
84-
n = len(people)
85-
ps = [0] * n
86-
for i, skills in enumerate(people):
87-
for skill in skills:
88-
ps[i] |= 1 << d[skill]
89-
return dfs(0, 0)
87+
m, n = len(req_skills), len(people)
88+
p = [0] * n
89+
for i, ss in enumerate(people):
90+
for s in ss:
91+
p[i] |= 1 << d[s]
92+
f = [inf] * (1 << m)
93+
g = [0] * (1 << m)
94+
h = [0] * (1 << m)
95+
f[0] = 0
96+
for i in range(1 << m):
97+
if f[i] == inf:
98+
continue
99+
for j in range(n):
100+
if f[i] + 1 < f[i | p[j]]:
101+
f[i | p[j]] = f[i] + 1
102+
g[i | p[j]] = j
103+
h[i | p[j]] = i
104+
i = (1 << m) - 1
105+
ans = []
106+
while i:
107+
ans.append(g[i])
108+
i = h[i]
109+
return ans
90110
```
91111

92112
### **Java**
@@ -95,58 +115,173 @@ class Solution:
95115

96116
```java
97117
class Solution {
98-
private int m;
99-
private int n;
100-
private int[] ps;
101-
private int[][][] f;
102-
private static final int MX = 100;
103-
104118
public int[] smallestSufficientTeam(String[] req_skills, List<List<String>> people) {
105-
m = req_skills.length;
106-
n = people.size();
107-
ps = new int[n];
108-
f = new int[n][1 << m][];
109119
Map<String, Integer> d = new HashMap<>();
120+
int m = req_skills.length;
121+
int n = people.size();
110122
for (int i = 0; i < m; ++i) {
111123
d.put(req_skills[i], i);
112124
}
125+
int[] p = new int[n];
113126
for (int i = 0; i < n; ++i) {
114-
for (String skill : people.get(i)) {
115-
ps[i] |= 1 << d.get(skill);
127+
for (var s : people.get(i)) {
128+
p[i] |= 1 << d.get(s);
116129
}
117130
}
118-
return dfs(0, 0);
131+
int[] f = new int[1 << m];
132+
int[] g = new int[1 << m];
133+
int[] h = new int[1 << m];
134+
final int inf = 1 << 30;
135+
Arrays.fill(f, inf);
136+
f[0] = 0;
137+
for (int i = 0; i < 1 << m; ++i) {
138+
if (f[i] == inf) {
139+
continue;
140+
}
141+
for (int j = 0; j < n; ++j) {
142+
if (f[i] + 1 < f[i | p[j]]) {
143+
f[i | p[j]] = f[i] + 1;
144+
g[i | p[j]] = j;
145+
h[i | p[j]] = i;
146+
}
147+
}
148+
}
149+
List<Integer> ans = new ArrayList<>();
150+
for (int i = (1 << m) - 1; i != 0; i = h[i]) {
151+
ans.add(g[i]);
152+
}
153+
return ans.stream().mapToInt(Integer::intValue).toArray();
119154
}
155+
}
156+
```
120157

121-
private int[] dfs(int i, int state) {
122-
if (i == n) {
123-
return state == (1 << m) - 1 ? new int[0] : add(new int[0], MX);
158+
### **C++**
159+
160+
```cpp
161+
class Solution {
162+
public:
163+
vector<int> smallestSufficientTeam(vector<string>& req_skills, vector<vector<string>>& people) {
164+
unordered_map<string, int> d;
165+
int m = req_skills.size(), n = people.size();
166+
for (int i = 0; i < m; ++i) {
167+
d[req_skills[i]] = i;
168+
}
169+
int p[n];
170+
memset(p, 0, sizeof(p));
171+
for (int i = 0; i < n; ++i) {
172+
for (auto& s : people[i]) {
173+
p[i] |= 1 << d[s];
174+
}
124175
}
125-
if (f[i][state] != null) {
126-
return f[i][state];
176+
int f[1 << m];
177+
int g[1 << m];
178+
int h[1 << m];
179+
memset(f, 63, sizeof(f));
180+
f[0] = 0;
181+
for (int i = 0; i < 1 << m; ++i) {
182+
if (f[i] == 0x3f3f3f3f) {
183+
continue;
184+
}
185+
for (int j = 0; j < n; ++j) {
186+
if (f[i] + 1 < f[i | p[j]]) {
187+
f[i | p[j]] = f[i] + 1;
188+
g[i | p[j]] = j;
189+
h[i | p[j]] = i;
190+
}
191+
}
127192
}
128-
int[] ans1 = dfs(i + 1, state);
129-
int[] ans2 = dfs(i + 1, state | ps[i]);
130-
if (ans1.length > 0 && ans1[0] == MX && ans2.length > 0 && ans2[0] == MX) {
131-
return f[i][state] = ans1;
193+
vector<int> ans;
194+
for (int i = (1 << m) - 1; i; i = h[i]) {
195+
ans.push_back(g[i]);
132196
}
133-
if (ans1.length > 0 && ans1[0] == MX) {
134-
return f[i][state] = add(ans2, i);
197+
return ans;
198+
}
199+
};
200+
```
201+
202+
### **Go**
203+
204+
```go
205+
func smallestSufficientTeam(req_skills []string, people [][]string) (ans []int) {
206+
d := map[string]int{}
207+
for i, s := range req_skills {
208+
d[s] = i
209+
}
210+
m, n := len(req_skills), len(people)
211+
p := make([]int, n)
212+
for i, ss := range people {
213+
for _, s := range ss {
214+
p[i] |= 1 << d[s]
215+
}
216+
}
217+
const inf = 1 << 30
218+
f := make([]int, 1<<m)
219+
g := make([]int, 1<<m)
220+
h := make([]int, 1<<m)
221+
for i := range f {
222+
f[i] = inf
223+
}
224+
f[0] = 0
225+
for i := range f {
226+
if f[i] == inf {
227+
continue
228+
}
229+
for j := 0; j < n; j++ {
230+
if f[i]+1 < f[i|p[j]] {
231+
f[i|p[j]] = f[i] + 1
232+
g[i|p[j]] = j
233+
h[i|p[j]] = i
234+
}
235+
}
236+
}
237+
for i := 1<<m - 1; i != 0; i = h[i] {
238+
ans = append(ans, g[i])
239+
}
240+
return
241+
}
242+
```
243+
244+
### **TypeScript**
245+
246+
```ts
247+
function smallestSufficientTeam(
248+
req_skills: string[],
249+
people: string[][],
250+
): number[] {
251+
const d: Map<string, number> = new Map();
252+
const m = req_skills.length;
253+
const n = people.length;
254+
for (let i = 0; i < m; ++i) {
255+
d.set(req_skills[i], i);
256+
}
257+
const p: number[] = new Array(n).fill(0);
258+
for (let i = 0; i < n; ++i) {
259+
for (const s of people[i]) {
260+
p[i] |= 1 << d.get(s)!;
135261
}
136-
if (ans2.length > 0 && ans2[0] == MX) {
137-
return f[i][state] = ans1;
262+
}
263+
const inf = 1 << 30;
264+
const f: number[] = new Array(1 << m).fill(inf);
265+
const g: number[] = new Array(1 << m).fill(0);
266+
const h: number[] = new Array(1 << m).fill(0);
267+
f[0] = 0;
268+
for (let i = 0; i < 1 << m; ++i) {
269+
if (f[i] === inf) {
270+
continue;
138271
}
139-
if (ans1.length < ans2.length + 1) {
140-
return f[i][state] = ans1;
272+
for (let j = 0; j < n; ++j) {
273+
if (f[i] + 1 < f[i | p[j]]) {
274+
f[i | p[j]] = f[i] + 1;
275+
g[i | p[j]] = j;
276+
h[i | p[j]] = i;
277+
}
141278
}
142-
return f[i][state] = add(ans2, i);
143279
}
144-
145-
private int[] add(int[] nums, int x) {
146-
int[] copy = Arrays.copyOf(nums, nums.length + 1);
147-
copy[copy.length - 1] = x;
148-
return copy;
280+
const ans: number[] = [];
281+
for (let i = (1 << m) - 1; i; i = h[i]) {
282+
ans.push(g[i]);
149283
}
284+
return ans;
150285
}
151286
```
152287

0 commit comments

Comments
 (0)