运动员和训练师的最大匹配数 图解题解
这道题到底在问什么
- 输入
- players=[4,7,9], trainers=[8,2,5,8]
- 输出
- 2
- 输入
- players=[1,1,1], trainers=[10]
- 输出
- 1
最优解:一步一步想明白
- 3记牢这一句:排完序后,让最弱的运动员去配够得上他的最弱训练师。这样强的训练师就被省下来留给强运动员,谁都不浪费,配出来的对数就是最多的。下面从最弱的运动员开始,一位一位配。
- 4先看没排序的原始数据。上面横排是训练师的能力 7、2、9、3、11、7、4,侧栏是运动员的能力 8、5、13、6、10。这样乱着放没法贪心,贪心的前提是两边都得从小到大排好队,这样才能让最弱的先配最弱的。
- 5两边各自排好序。训练师从小到大是 2、3、4、7、7、9、11,运动员从小到大是 5、6、8、10、13。现在准备工作做完了,让指针 j 从最左边的训练师开始,依次给每位运动员找搭档。
- 6规则再明确一下:侧栏最上面高亮的是当前轮到的运动员,永远从最弱的那位开始;主舞台上高亮的是指针 j 当前指着的训练师。给这位运动员找搭档时,j 只会往右走,不回头。够格就染绿配对,太弱就染灰跳过。开始。
- 7轮到能力 5 的运动员。指针 j 没有回头,接着从上一位停下的地方往右看,现在指着能力 2 的训练师。看看这位训练师托不托得起 5。
- 8训练师能力 2 比运动员 5 还小,带不动他,配不了。而且后面的运动员只会更强,这位训练师对谁都没用了,直接染灰划掉,指针 j 往右挪一格。
- 9指针 j 落到能力 3 的训练师上,继续拿它和运动员 5 比,看这次够不够格。
- 10训练师能力 3 比运动员 5 还小,带不动他,配不了。而且后面的运动员只会更强,这位训练师对谁都没用了,直接染灰划掉,指针 j 往右挪一格。
- 11指针 j 落到能力 4 的训练师上,继续拿它和运动员 5 比,看这次够不够格。
- 12训练师能力 4 比运动员 5 还小,带不动他,配不了。而且后面的运动员只会更强,这位训练师对谁都没用了,直接染灰划掉,指针 j 往右挪一格。
- 13指针 j 落到能力 7 的训练师上,继续拿它和运动员 5 比,看这次够不够格。
- 14训练师能力 7 大于等于运动员 5,托得起!这一对成了,把这位训练师染绿。运动员 5 也算配上了。已匹配数加到 1。接着两个指针一起往后挪,服务下一位更强的运动员。
- 15轮到能力 6 的运动员。指针 j 没有回头,接着从上一位停下的地方往右看,现在指着能力 7 的训练师。看看这位训练师托不托得起 6。
- 16训练师能力 7 大于等于运动员 6,托得起!这一对成了,把这位训练师染绿。运动员 6 也算配上了。已匹配数加到 2。接着两个指针一起往后挪,服务下一位更强的运动员。
- 17轮到能力 8 的运动员。指针 j 没有回头,接着从上一位停下的地方往右看,现在指着能力 9 的训练师。看看这位训练师托不托得起 8。
- 18训练师能力 9 大于等于运动员 8,托得起!这一对成了,把这位训练师染绿。运动员 8 也算配上了。已匹配数加到 3。接着两个指针一起往后挪,服务下一位更强的运动员。
- 19轮到能力 10 的运动员。指针 j 没有回头,接着从上一位停下的地方往右看,现在指着能力 11 的训练师。看看这位训练师托不托得起 10。
- 20训练师能力 11 大于等于运动员 10,托得起!这一对成了,把这位训练师染绿。运动员 10 也算配上了。已匹配数加到 4。接着两个指针一起往后挪,服务下一位更强的运动员。
- 21轮到能力 13 的运动员,可指针 j 已经扫到训练师队伍的尽头,一个能用的训练师都不剩了。这位运动员再强也没人带,只能落空。
- 22既然连最弱的运动员之后的强手都配光了训练师,后面比他更强的运动员更不可能有搭档,直接收工。此刻已经配好的对数就是答案 4。
- 23回看全程。运动员 5、6、8、10 各自配到了一位刚好够得上的训练师,四位训练师染成绿色;被跳过的弱训练师染灰。最强的运动员 13 到最后没有训练师托得起,落空了。数一数绿色的对子,一共 4 对,这就是最大匹配数。
⚠️ 容易写错的地方
✗ 错:不排序直接双指针
✓ 对:两个数组都必须先从小到大排序
贪心成立的前提是「最弱运动员配够得上的最弱训练师」,不排序就没有从小到大的顺序,贪心的正确性直接崩掉
✗ 错:让强运动员优先挑训练师
✓ 对:永远让最弱的运动员先配
强运动员挑走本可留给他的训练师没问题,但若强者先挑走了一个刚够弱者用的训练师,弱者反而可能没得配,总对数变少
✗ 错:配对后指针 j 不前进
✓ 对:配成一对后 j 必须往后挪
一位训练师只能带一名运动员,配上后这位训练师就用掉了,j 不前进会让同一位训练师被重复使用
✗ 错:用严格小于判断能配
✓ 对:能力相等也能配,判断要用小于等于
题目说运动员能力小于等于训练师能力即可配对,相等是允许的,用严格小于会漏掉相等这类合法配对
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def matchPlayersAndTrainers(self, players: List[int], trainers: List[int]) -> int:
players.sort()
trainers.sort()
j, n = 0, len(trainers)
for i, p in enumerate(players):
while j < n and trainers[j] < p:
j += 1
if j == n:
return i
j += 1
return len(players)C++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
int matchPlayersAndTrainers(vector<int>& players, vector<int>& trainers) {
sort(players.begin(), players.end());
sort(trainers.begin(), trainers.end());
int m = players.size(), n = trainers.size();
for (int i = 0, j = 0; i < m; ++i, ++j) {
while (j < n && trainers[j] < players[i]) {
++j;
}
if (j == n) {
return i;
}
}
return m;
}
};Java
import java.util.*;
class Solution {
public int matchPlayersAndTrainers(int[] players, int[] trainers) {
Arrays.sort(players);
Arrays.sort(trainers);
int m = players.length, n = trainers.length;
for (int i = 0, j = 0; i < m; ++i, ++j) {
while (j < n && trainers[j] < players[i]) {
++j;
}
if (j == n) {
return i;
}
}
return m;
}
}复杂度
时间
O(m log m + n log n)
m 名运动员、n 位训练师。主要开销是两次排序,分别是 m log m 和 n log n;后面的双指针扫描里 i 和 j 各自只从头走到尾、不回头,是 O(m + n),被排序开销盖过
空间
O(1) 辅助 · 排序内部因语言而异
不额外开数组,只用几个指针变量,辅助空间 O(1)。排序内部开销因语言而异:C 加加和 Java 通常是 O(log m + log n) 级的递归栈,Python 的排序最坏可到 O(m + n);若把排序内部也算上,空间随语言在这两档之间
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 运动员和训练师的最大匹配数 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这题的核心思路一句话怎么说?+
把运动员和训练师两个能力数组都从小到大排序,然后双指针贪心:让最弱的运动员去配够得上他的最弱训练师,配上就两个指针一起前进,配不上就把太弱的训练师跳过。所有运动员轮完或训练师用光时,配成的对数就是最大匹配数。
为什么这个贪心是对的,能证明吗?+
可以用交换论证。假设最优解里最弱的运动员没有配那位够得上他的最弱训练师,而是配了更强的训练师,那我们总能把他换成配最弱的够格训练师,腾出的强训练师留给别人,匹配对数不减。反复这样调整,就能变成我们贪心产出的方案,所以贪心的对数不会少于任何最优解,即为最优。
复杂度是多少,瓶颈在哪?+
瓶颈是两次排序,时间 O(m log m 加 n log n);排完序后的双指针扫描 i 和 j 都只走一遍、不回头,是线性的 O(m 加 n),被排序盖过。空间除排序内部开销外只用常数个指针,是 O(1)。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 运动员和训练师的最大匹配数 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。