Leetcode.826 安排工作以达到最大收益

题目链接

Leetcode.826 安排工作以达到最大收益 Rating : 1709

题目描述

你有 n个工作和 m个工人。给定三个数组: difficulty, profit 和 worker,其中:

  • difficulty[i]表示第 i个工作的难度,profit[i]表示第 i个工作的收益。
  • worker[i]是第 i个工人的能力,即该工人只能完成难度小于等于 worker[i]的工作。

每个工人 最多 只能安排 一个 工作,但是一个工作可以 完成多次

  • 举个例子,如果 3 个工人都尝试完成一份报酬为 $1 的同样工作,那么总收益为 $3 。如果一个工人不能完成任何工作,他的收益为 $0 。

返回 在把工人分配到工作岗位后,我们所能获得的最大利润 。

示例 1:

输入: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7]
输出: 100
解释: 工人被分配的工作难度是 [4,4,6,6] ,分别获得 [20,20,30,30] 的收益。

示例 2:

输入: difficulty = [85,47,57], profit = [24,66,99], worker = [40,25,25]
输出: 0

提示:
  • n = = d i f f i c u l t y . l e n g t h n == difficulty.length n==difficulty.length
  • n = = p r o f i t . l e n g t h n == profit.length n==profit.length
  • m = = w o r k e r . l e n g t h m == worker.length m==worker.length
  • 1 < = n , m < = 1 0 4 1 <= n, m <= 10^4 1<=n,m<=104
  • 1 < = d i f f i c u l t y [ i ] , p r o f i t [ i ] , w o r k e r [ i ] < = 1 0 5 1 <= difficulty[i], profit[i], worker[i] <= 10^5 1<=difficulty[i],profit[i],worker[i]<=105

分析:

我们先用一个集合 v来装(difficulty,profit)这样的二元组。

接着再对 集合vdifficulty排序。

例如: difficulty = [85,47,57], profit = [24,66,99]。排序后的集合就为 v = [ [47,66] , [57,99] , [85,25] ]

如果有一个工人的能力是 100,那么他应该选择的就是这一项 [57,99],即最大收益 99

注意: 实际上我们只关心每一个工人能取得的最大收益,并不关心具体要选择哪一个难度的工作

将排序后的集合v稍加处理,让其只记录前面任务的最大收益,即 v = [ [47,66] , [57,99] , [85,99] ]。这样的话,我们就可以使用 二分 的方式,求得第一个小于等于某一个工人极限的最大收益。

时间复杂度: O ( n ∗ l o g n ) O(n*logn) O(nlogn)

C++代码:

using PII = pair<int,int>;
class Solution {
public:
    int maxProfitAssignment(vector<int>& difficulty, vector<int>& profit, vector<int>& worker) {
        int n = difficulty.size();
        vector<PII> a;

        for(int i = 0;i < n;i++){
            a.push_back({difficulty[i],profit[i]});
        }
        //pair<int,int> 是默认先按第一个参数排序,第一个参数相等的话再按第二个参数排序
        sort(a.begin(),a.end());
        
        //只记录到当前难度的最大收益
        for(int i = 1;i < n;i++){
            a[i].second = max(a[i].second,a[i-1].second);
        }

        int ans = 0;
        for(auto x:worker){
            //对于每一个工人,直接二分求最大的收益
            int l = 0,r = n - 1;
            while(l < r){
                int mid = (l + r + 1) >> 1;
                if(a[mid].first <= x) l = mid;
                else r = mid - 1;
            }

            if(a[l].first <= x) ans += a[l].second;
        }
        return ans;
    }
};

Java代码:

class Solution {
    public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
        List<int[]> list = new ArrayList<>();

        int n = difficulty.length;
        for(int i = 0;i < n;i++) list.add(new int[]{difficulty[i],profit[i]});
        
        //按 difficulty 从小到大排序
        Collections.sort(list,(a,b)->(a[0] - b[0]));

        for(int i = 1;i < n;i++){
            list.get(i)[1] = Math.max(list.get(i)[1],list.get(i-1)[1]);
        }

        int ans = 0;
        for(int x:worker){
            int l = 0,r = n - 1;
            while(l<r){
                int mid = (l + r + 1) >> 1;
                if(list.get(mid)[0] <= x) l = mid;
                else r = mid - 1;
            }
            if(list.get(l)[0] <= x) ans += list.get(l)[1];
        }
        return ans;
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值