AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

LeetCode 1235. 规划兼职工作    原题链接    困难

作者: 作者的头像   wzc1995 ,  2019-10-20 12:07:57 ,  所有人可见 ,  阅读 2738


8


2

题目描述

你打算利用空闲时间来做兼职工作赚些零花钱。

这里有 n 份兼职工作,每份工作预计从 startTime[i] 开始到 endTime[i] 结束,报酬为 profit[i]。

给你一份兼职工作表,包含开始时间 startTime,结束时间 endTime 和预计报酬 profit 三个数组,请你计算并返回可以获得的最大报酬。

注意,时间上出现重叠的 2 份工作不能同时进行。

如果你选择的工作在时间 X 结束,那么你可以立刻进行在时间 X 开始的下一份工作。

样例

输入:startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70]
输出:120
解释:
我们选出第 1 份和第 4 份工作, 
时间范围是 [1-3]+[3-6],共获得报酬 120 = 50 + 70。

输入:startTime = [1,2,3,4,6], endTime = [3,5,10,6,9], profit = [20,20,100,70,60]
输出:150
解释:
我们选择第 1,4,5 份工作。 
共获得报酬 150 = 20 + 70 + 60。

输入:startTime = [1,1,1], endTime = [2,3,4], profit = [5,6,4]
输出:6

限制

  • 1 <= startTime.length == endTime.length == profit.length <= 5 * 10^4
  • 1 <= startTime[i] < endTime[i] <= 10^9
  • 1 <= profit[i] <= 10^4

算法

(动态规划,二分) $O(n \log n)$
  1. 首先将所有工作按照结束时间从小到大排序。
  2. 设 $f(i)$ 表示考虑了前 $i$ 份工作,能获得的最大利润。
  3. 初始时 $f(0) = jobs[0][2]$,即第一份工作的利润。
  4. 对于第 $i$ 份工作,二分查找最大的 $j < i$,使得 jobs[j][1] <= jobs[i][0],转移 $f(i) = \max(f(i - 1), f(j) + jobs[i][2])$。若 $j$ 不存在,则转移 $f(j) = \max(f(i - 1), jobs[i][2])$。
  5. 最终答案为 $f(n - 1)$。

时间复杂度

  • 排序的时间复杂度为 $O(n \log n)$,动态规划 + 二分的时间复杂度为 $O(n \log n)$。
  • 故总时间复杂度为 $O(n \log n)$。

空间复杂度

  • 需要额外 $O(n)$ 的空间重新记录工作的信息方便排序,以及记录动态规划的状态。

C++ 代码

class Solution {
public:
    int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
        int n = startTime.size();

        vector<vector<int>> jobs(n);
        for (int i = 0; i < n; i++) {
            jobs[i].push_back(startTime[i]);
            jobs[i].push_back(endTime[i]);
            jobs[i].push_back(profit[i]);
        }

        auto cmp = [&](const vector<int> &x, const vector<int> &y) {
            return x[1] < y[1];
        };

        sort(jobs.begin(), jobs.end(), cmp);

        vector<int> f(n);

        f[0] = jobs[0][2];

        for (int i = 1; i < n; i++) {
            int l = 0, r = i - 1;
            while (l < r) {
                int mid = (l + r) >> 1;
                if (jobs[mid + 1][1] <= jobs[i][0])
                    l = mid + 1;
                else
                    r = mid;
            }

            if (jobs[l][1] <= jobs[i][0])
                f[i] = max(f[i - 1], f[l] + jobs[i][2]);
            else
                f[i] = max(f[i - 1], jobs[i][2]);

        }

        return f[n - 1];
    }
};

4 评论


用户头像
qbz666   2022-10-22 01:32         踩      回复

这题可不可以对左端点排序,然后右端点进行LIS,


用户头像
chillboy   2021-05-02 12:21         踩      回复

厉害!


用户头像
温柔大鸡翅   2020-09-11 01:00         踩      回复

对于第 ii 份工作,二分查找最大的 j<ij<i,使得 jobs[j][1] <= jobs[j][0],转移 这里是不是该 jobs[j][1] <= jobs[i][0]

用户头像
wzc1995   2020-09-11 22:00         踩      回复

手误已修正~


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息