You have n jobs and m workers. You are given three arrays: difficulty, profit, and worker where:
difficulty[i] and profit[i] are the difficulty and the profit of the ith job, and
worker[j] is the ability of jth worker (i.e., the jth worker can only complete a job with difficulty at most worker[j]).
Every worker can be assigned at most one job , but one job can be completed multiple times .
For example, if three workers attempt the same job that pays $1, then the total profit will be $3. If a worker cannot complete any job, their profit is $0.
Return the maximum profit we can achieve after assigning the workers to the jobs.
Example 1:
1 2 3 Input: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7] Output: 100 Explanation: Workers are assigned jobs of difficulty [4,4,6,6] and they get a profit of [20,20,30,30] separately.
Example 2:
1 2 Input: difficulty = [85,47,57], profit = [24,66,99], worker = [40,25,25] Output: 0
题目大意 有 n 个工作和 m 个工人。给定三个数组:difficulty、profit 和 worker,其中:
difficulty[i] 和 profit[i] 分别是第 i 个工作的难度和收益
worker[j] 是第 j 个工人的能力(即该工人只能完成难度不超过 worker[j] 的工作)
每个工人最多只能分配一个工作,但一个工作可以被多个工人完成。返回分配工作后能获得的最大总利润。
核心解题思路
关联工作难度和收益 :将工作的难度和对应的收益关联起来,并按难度排序
预处理最大收益 :对于每个难度,计算该难度及以下能获得的最大收益(因为可能存在低难度高收益的工作)
为每个工人分配最优工作 :对于每个工人,找到其能力范围内能获得的最大收益
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution { public: int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) { // 将工作难度和收益配对 vector<pair<int, int>> jobs; for (int i = 0; i < difficulty.size(); ++i) { jobs.emplace_back(difficulty[i], profit[i]); } // 按工作难度排序 sort(jobs.begin(), jobs.end()); // 预处理:计算每个难度下的最大收益 vector<int> maxProfit; int currentMax = 0; for (auto& job : jobs) { currentMax = max(currentMax, job.second); maxProfit.push_back(currentMax); } // 为每个工人找到能完成的最高收益工作 int totalProfit = 0; for (int ability : worker) { // 找到第一个难度大于工人能力的工作 int left = 0, right = jobs.size(); while (left < right) { int mid = left + (right - left) / 2; if (jobs[mid].first > ability) { right = mid; } else { left = mid + 1; } } // 如果存在能完成的工作,累加最大收益 if (left > 0) { totalProfit += maxProfit[left - 1]; } } return totalProfit; } };
解法2:双指针 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <vector> #include <algorithm> using namespace std; class Solution { public: int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) { int n = difficulty.size(); // 将工作难度和收益配对 vector<pair<int, int>> jobs(n); for (int i = 0; i < n; i++) { jobs[i] = {difficulty[i], profit[i]}; } // 对工作按难度排序,对工人按能力排序 sort(jobs.begin(), jobs.end()); sort(worker.begin(), worker.end()); int ans = 0; // 总收益 int j = 0; // 工作指针 int max_profit = 0; // 当前能力范围内的最大收益 // 遍历每个工人 for (int w : worker) { // 找到该工人能完成的所有工作,并更新最大收益 while (j < n && jobs[j].first <= w) { max_profit = max(max_profit, jobs[j++].second); } // 累加当前工人能获得的最大收益 ans += max_profit; } return ans; } };
数据准备与排序 :
将工作的难度和收益组成 pair 数组
对工作按难度从小到大排序
对工人按能力从小到大排序
排序后,能力小的工人在前,难度低的工作在前
双指针遍历 :
工人指针:循环遍历每个工人(已按能力排序)
工作指针j:从 0 开始,指向当前需要检查的工作
对于每个工人,将工作指针向前移动到其能力无法完成的工作为止
在此过程中,动态维护max_profit,即当前工人能完成的所有工作中的最大收益
收益计算 :
每个工人的贡献是当前max_profit(其能力范围内的最大收益)
累加所有工人的贡献得到总收益
解法3:map 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { public: int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) { // 创建一个map存储难度到最大收益的映射,按难度自动排序 map<int, int> diffToProfit; // 首先填充map,保留每个难度的最大收益 for (int i = 0; i < difficulty.size(); ++i) { int d = difficulty[i]; int p = profit[i]; // 如果难度已存在,保留最大的收益 if (diffToProfit.find(d) != diffToProfit.end()) { diffToProfit[d] = max(diffToProfit[d], p); } else { diffToProfit[d] = p; } } // 预处理map,确保每个难度对应的是当前及之前的最大收益 int maxProfit = 0; for (auto& entry : diffToProfit) { maxProfit = max(maxProfit, entry.second); entry.second = maxProfit; } // 计算总收益 int total = 0; for (int ability : worker) { // 找到第一个大于当前能力的难度 auto it = diffToProfit.upper_bound(ability); // 如果存在不大于当前能力的难度,累加其最大收益 if (it != diffToProfit.begin()) { --it; total += it->second; } // 否则该工人无法完成任何工作,贡献为0 } return total; } };