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

题目链接

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

题目描述

你有 n n n 个工作和 m m m 个工人。给定三个数组: d i f f i c u l t y difficulty difficulty, p r o f i t profit profit w o r k e r worker worker ,其中:

  • d i f f i c u l t y [ i ] difficulty[i] difficulty[i] 表示第 i i i 个工作的难度, p r o f i t [ i ] profit[i] profit[i] 表示第 i i i 个工作的收益。
  • w o r k e r [ i ] worker[i] worker[i] 是第 i 个工人的能力,即该工人只能完成难度小于等于 w o r k e r [ i ] worker[i] worker[i] 的工作。

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

  • 举个例子,如果 3 3 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 \leq n, m \leq 10^4 1n,m104
  • 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 \leq difficulty[i], profit[i], worker[i] \leq 10^5 1difficulty[i],profit[i],worker[i]105

解法:排序 + 二分 + 贪心

我们先对 a ( d i f f i c u l t y , p r o f i t ) a(difficulty,profit) a(difficulty,profit) 这样的二元组按照 d i f f i c u l t y difficulty difficulty 从小到大的顺序排序。

假设数据是这样的形式 : ( 68 , 67 ) , ( 35 , 17 ) , ( 52 , 1 ) , ( 47 , 81 ) , ( 86 , 3 ) (68,67),(35,17),(52,1),(47,81),(86,3) (68,67),(35,17),(52,1),(47,81),(86,3)

那么按照 d i f f i c u l t y difficulty difficulty 从小到大排序之后的数据为: ( 35 , 17 ) , ( 47 , 81 ) , ( 52 , 1 ) , ( 68 , 67 ) , ( 86 , 3 ) (35,17),(47,81),(52,1),(68,67),(86,3) (35,17),(47,81),(52,1),(68,67),(86,3),如下图所示:

在这里插入图片描述
目前有一名工人的能力值为 x x x,假设当前 x = 60 x = 60 x=60,那么这名工人可以选择的工作就是前三项。因为已经按照 d i f f i c u l t y difficulty difficulty 排序了,所以可以通过二分的方式快速得到某一个工人可以选择工作的范围。

在这里插入图片描述
通过观察,可以发现选取第二份工作获得的收益最大,收益为 81 81 81

那么怎么样才能快速的获取最大收益呢?因为直接排序的时间复杂度是 O ( n 2 × l o g n ) O(n^2 \times logn) O(n2×logn),在 n = 1 0 4 n = 10^4 n=104的数量级下肯定会超时。

因为我们只关注最大收益,其他的收益都可以忽略掉。所以在排序之后,我们可以对 p r o f i t profit profit 做如下的预处理:

在这里插入图片描述

在做了以上的预处理操作之后,我们在确定了工人可以选择的工作范围之后,同时也能得到最大收益。此时的最大收益就是工人能够选择最大难度工作对应的收益。

按照上述的例子,工人的能力值 x = 60 x = 60 x=60,他能够选择的工作是前三项,也就是 [ 0 , 2 ] [0,2] [0,2],那么最大收益就是 a [ 2 ] . p r o f i t a[2].profit a[2].profit

时间复杂度: O ( n × l o g n + n ) O(n \times logn + n) O(n×logn+n)

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]});
        }

        ranges::sort(a);

        //预处理 只关注最大值
        for(int i = 1;i < n;i++)
        {
            a[i].second = max(a[i].second, a[i - 1].second);
        }

        auto check = [&](int x){
            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;
            }
            return l;
        };

        int ans = 0;

        for(auto x:worker)
        {
            int i = check(x);
            //当前工人困难度最低的工作都没资格选 直接跳过
            if(a[i].first > x) continue;
            ans += a[i].second;
        }

        return ans;
    }
};
  • 11
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值