[LeetCode] Most Profit Assigning Work 安排最大利润的工作
We have jobs: difficulty[i] is the difficulty of the ith job, and profit[i] is the profit of the ith job.
Now we have some workers. worker[i] is the ability of the ith worker, which means that this worker can only complete a job with difficulty at most worker[i].
Every worker can be assigned at most one job, but one job can be completed multiple times.
For example, if 3 people attempt the same job that pays $1, then the total profit will be $3. If a worker cannot complete any job, his profit is $0.
What is the most profit we can make?
Example 1:
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 profit of [20,20,30,30] seperately.
Notes:
1 <= difficulty.length = profit.length <= 100001 <= worker.length <= 10000difficulty[i], profit[i], worker[i]are in range[1, 10^5]
这道题给了我们一堆工作,每个工作有不同的难度,且对应着不同的利润。现在还有一些工人,每个人能胜任工作的难度不同,题目说了没人最多只能干一项工作,但是每个工作可以被多个人做。现在问我们这些工人能产生的最大利润。题目中给了一个例子,但是这个例子会给我们一些错觉,实际上difficulty数组不一定是有序的,而且可能有相同难度的工作对应不同的利润。还有就是,难度大的工作不一定利润就大,忽略了这些隐藏条件,很容易做错。为了快速的知道每个工作的难度和其对应的利润,我们可以建立难度和利润的之间映射,由于前面说了,相同的难度可能有不同的利润,所以我们希望难度映射到最高的利润,所以每次都跟自身的映射值比较一下,保留较大值即可。同时,我们还希望工作的难度能排个序,这样就可以根据工人的能力值来快速搜索能做的工作了,所以可以使用TreeMap。但是,还有个问题,前面说了难度大的工作不一定利润就大,所以我们希望难度映射的利润,是不大于其难度的工作的利润中的最大值,所以我们还要遍历一遍所有的映射,维护一个当前最大值cur,然后不断的更新每个工作的利润,同时也更新当前最大值。这些都建立好了后,之后就简单了,我们遍历每个工人,根据其能力值,来二分查第一个难度值大于该能力值的工作,可以用内置的 upper_bound 函数,如果结果第一个数字,那么我们将其前面一个难度的工作的利润加入结果res即可,参见代码如下:
解法一:
class Solution {
public:
int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) {
int res = , cur = ;
map<int, int> m;
for (int i = ; i < difficulty.size(); ++i) {
m[difficulty[i]] = max(m[difficulty[i]], profit[i]);
}
for (auto &a : m) {
a.second = max(a.second, cur);
cur = a.second;
}
for (int i = ; i < worker.size(); ++i) {
auto it = m.upper_bound(worker[i]);
if (it != m.begin()) {
res += (--it)->second;
}
}
return res;
}
};
我们也可以不用TreeMap,而是将难度和利润组成pair,加入到一个数组中,那么就算相同的难度对应不同的利润,也不会丢失数据。我们还是根据难度给所有的工作排个序,同时,我们按能力也给工人排个序,从能力低的工人开始分配工作,这样我们只需要遍历一次所有的工作,因为当能力低的工人分配了某个工作时,后面能力高的工人不需要再考虑之前的工作,因为工作已经按难度排好序了,只需要从当前位置继续往后面匹配工作,我们可以使用一个全局变量i,当工人的能力值大于等于某个工作的难度时,我们用其来更新curMax,这里的curMax记录当前工人能做的工作的最大利润,这样当工作遍历完了,或者当前工作难度已经大于工人的能力值了时就停止,这样curMax就是该工人能获得的利润,加入结果res,参见代码如下:
解法二:
class Solution {
public:
int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) {
int res = , n = profit.size(), curMax = , i = ;
vector<pair<int, int>> jobs;
for (int j = ; j < n; ++j) {
jobs.push_back({difficulty[j], profit[j]});
}
sort(jobs.begin(), jobs.end());
sort(worker.begin(), worker.end());
for (int ability : worker) {
while (i < n && ability >= jobs[i].first) {
curMax = max(curMax, jobs[i++].second);
}
res += curMax;
}
return res;
}
};
我们还可以使用动态规划Dynamic Programming来做,建立一个一维的dp数组,这里的dp[i]表示能力为i的工人所能获得的最大的利润。dp数组大小初始化为100001,这是题目中给定的范围,然后我们用给定的工作的难度和利润来更新dp数组,跟解法一中的更新TreeMap有些像,要考虑相同的难度可能有不同的利润,所以每次更新的时候要跟本身比较。之后就是从1开始更新dp本身,dp[i]跟前面一个dp值比较,取较大值更新dp[i],这个操作跟解法一中的那个更新TreeMap的映射值的操作是一样的,都是为了避免难度高的工作利润低。这里的dp数组cover了所有的能力值的范围,这样对于任何一个工人,我们可以根据其能力值马上找出其可以获得的最大利润,而不用像解法一中要使用二分查找,我们牺牲了空间,换来了常数级的查找速度,参见代码如下:
解法三:
class Solution {
public:
int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) {
int res = , n = profit.size();
vector<int> dp();
for (int i = ; i < n; ++i) {
dp[difficulty[i]] = max(dp[difficulty[i]], profit[i]);
}
for (int i = ; i < dp.size(); ++i) {
dp[i] = max(dp[i], dp[i - ]);
}
for (int ability : worker) {
res += dp[ability];
}
return res;
}
};
参考资料:
https://leetcode.com/problems/most-profit-assigning-work/
https://leetcode.com/problems/most-profit-assigning-work/discuss/127133/Java-Solution-with-TreeMap
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Most Profit Assigning Work 安排最大利润的工作的更多相关文章
- [Swift]LeetCode826. 安排工作以达到最大收益 | Most Profit Assigning Work
We have jobs: difficulty[i] is the difficulty of the ith job, and profit[i] is the profit of the ith ...
- LeetCode 826. Most Profit Assigning Work
原题链接在这里:https://leetcode.com/problems/most-profit-assigning-work/ 题目: We have jobs: difficulty[i] is ...
- 【LeetCode】826. Most Profit Assigning Work 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址: https://leetcode.com/problems/most-pro ...
- 826. Most Profit Assigning Work
https://leetcode.com/problems/most-profit-assigning-work/description/ class Solution { public: int m ...
- [LeetCode] 207. Course Schedule 课程安排
There are a total of n courses you have to take, labeled from 0 to n - 1. Some courses may have prer ...
- [LeetCode]621. Task Scheduler 任务安排 题解
题目描述 给定一个char数组,代表CPU需要做的任务,包含A-Z,不用考虑顺序,每个任务能在1个单位完成.但是有规定一个非负整数n代表两个相同任务之间需要至少n个时间单位.球最少数量的时间单位完成所 ...
- SEOer怎样安排一天的工作
昨天一文谈到seo车型优化恐惧了,一些兄弟果断说,不玩seo.妮子不是吓人的,希望大家好好看清自己如今行业现状,怎样突破下步,如今仅仅剩下竞价和B2B付费平台了吗?每天坚持博客更新,尽管不像那些名博那 ...
- Swift LeetCode 目录 | Catalog
请点击页面左上角 -> Fork me on Github 或直接访问本项目Github地址:LeetCode Solution by Swift 说明:题目中含有$符号则为付费题目. 如 ...
- leetcode 第188题,我的解法,Best Time to Buy and Sell Stock IV
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...
随机推荐
- 五道java小题,补更四道java小题
一:分析以下需求,并用代码实现 1.定义List集合,存入多个字符串 2.删除集合中字符串"def" 3.然后利用迭代器遍历集合元素并输出 import j ...
- ASP.NET WebApi 自带Json返回日期带T无法格式化的问题
WebApi自带json序列化对遇到时间日期字段的时候,到前端获取的格式总是为“ 2016-07-14T15:32:44”,中间总是会带一个T,显然不是很友好.先是偷懒在园子里边去找一些解决方案,尝试 ...
- 第三节:Action向View传值的四种方式(ViewData、ViewBag、TempData、Model)
简 介 在前面的章节中,我们已经很清楚,MVC工作模型的流程,Controller中的Action接收到客户端的请求,处理后要将数据返回给View,那么Action中是如何将数据返回给View的,二 ...
- .NET面试题系列(十七)前端面试
JavaScript js如何实现继承 CSS 行内元素和块状元素的区别 CSS让2个DIV在同一行显示的解决方法 在CSS中,div属于块级元素,每个块级元素默认占一行高度,一行内添加一个块级 ...
- [物理学与PDEs]第2章第2节 粘性流体力学方程组 2.6 一维粘性热传导流体动力学方程组
一维粘性热传导流体动力学方程组: $$\beex \bea \cfrac{\p\rho}{\p t}+\cfrac{\p }{\p x}(\rho u)&=0,\\ \cfrac{\p u}{ ...
- 【codeforces 914H】Ember and Storm's Tree Game
原题链接 Description Ember和Storm正在玩游戏.首先,Ember构造一棵n个节点且每个节点度数不超过d的带节点编号的树T.然后,Storm选择两个不同的节点u和v,并写下从u到v路 ...
- Django2.1,Xadmin2.0下的问题记录
此篇博文长期更新…… 环境: Ubuntu18.04, Python3.6, Django2.1, Xadmin2.0 1. Xadmin添加用户小组件时报错:xadmin render() got ...
- centos 搭建 leanote
centos 搭建leanote(蚂蚁笔记) 至于蚂蚁笔记是什么可以看官网的介绍,https://leanote.com/ ,我只能说 nice,你值得拥有. 开始搭建(源码安装,安装路径在 /et ...
- 【原创】大数据基础之Kudu(2)移除dead tsever
当kudu有tserver下线或者迁移或者修改hostname之后,旧的tserver会一直以dead状态出现,并且tserver日志中会有大量的连接重试日志,一天的错误日志会有几个G, W0322 ...
- Python-Django 模型层-多表查询-2
-related_name:基于双下划线的跨表查询,修改反向查询的字段 -related_query_name:基于对象的跨表查询,修改反向查询字段 publish = ForeignKey(Blog ...