20240105-工作安排的最大收益

题目要求

我们有 n 份工作,每份工作都安排在 startTime[i] 至 endTime[i] 期间完成,从而获得 profit[i] 的利润。

给你 startTime、endTime 和 profit 数组,返回你能获得的最大利润,使得子集中没有两个时间范围重叠的工作。

如果你选择了一项在 X 时间结束的工作,你就可以开始另一项在 X 时间开始的工作。

例子

Input: startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70]
Output: 120
Explanation: The subset chosen is the first and fourth job. 
Time range [1-3]+[3-6] , we get profit of 120 = 50 + 70.

Input: startTime = [1,2,3,4,6], endTime = [3,5,10,6,9], profit = [20,20,100,70,60]
Output: 150
Explanation: The subset chosen is the first, fourth and fifth job. 
Profit obtained 150 = 20 + 70 + 60.

Input: startTime = [1,1,1], endTime = [2,3,4], profit = [5,6,4]
Output: 6

思路

这个题目看起来似乎是一个递归问题(背包),在有限的时间内放下最多的工作(产生最大的价值?)但是仔细一想每个工作由起始结束时间决定,并不仅仅是工作时长的大小(可以直接放到背包中)。因此我又想是否使用深度优先搜索解决这个问题。似乎可行...

这次的深度优先搜索需要遍历所有的可能情况,然后返回最优的profit值。

终止条件

那么深搜的终止条件是什么,显而易见就是最后一个工作的截至时间之后,不能再有其他的工作,即:

if (当前工作的截止时间之后没有其他工作) {maxprofit = max(profit, maxprofit);return;}
bool hasNext = false;for (int i = start + 1; i < startTime.size(); ++i) {if (endTime[start] < startTime[i]) {hasNext = true;break;}}if (!hasNext) {maxprofit = max(maxprofit, currentProfit);return;}

回溯

for (int i = start; i < startTime.size(); ++i) {currentProfit += profit[i];backtracking(i+1, currentProfit, startTime, endTime, profit);currentProfit -= profit[i];}

 目前已经完成了回溯:深搜(其实好像不太能抽象成一棵树)算法,但是目前还没有正确的处理时间冲突(即i+1的部分),修改后代码如下,

class Solution {
public:int maxprofit = -1;void backtracking(int startIndex, int lastEnd, int currentProfit, const vector<int>& startTime, const vector<int>& endTime, const vector<int>& profit) {// bool hasNext = false;// for (int i = 0; i < startTime.size(); ++i) {//     if (lastEnd < startTime[i]) {//         hasNext = true;//         break;//     }// }// if (!hasNext) {//     maxprofit = max(maxprofit, currentProfit);//     return;// }maxprofit = max(maxprofit, currentProfit);for (int i = startIndex; i < startTime.size(); ++i) {if (startTime[i] < lastEnd) {continue;}currentProfit += profit[i];printf("Position: %d, currentProfit: %d, maxProfit: %d", i, currentProfit, maxprofit);backtracking(i+1, endTime[i], currentProfit, startTime, endTime, profit);currentProfit -= profit[i];}}int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {int n = startTime.size();vector<int> jobs(n);iota(jobs.begin(), jobs.end(), 0); // 填充索引// 根据 startTime 排序索引sort(jobs.begin(), jobs.end(), [&](int a, int b) {return startTime[a] < startTime[b];});// 重新排列 startTime、endTime 和 profitvector<int> sortedStartTime(n), sortedEndTime(n), sortedProfit(n);for (int i = 0; i < n; ++i) {sortedStartTime[i] = startTime[jobs[i]];sortedEndTime[i] = endTime[jobs[i]];sortedProfit[i] = profit[jobs[i]];}backtracking(0, -1, 0, sortedStartTime, sortedEndTime, sortedProfit);return maxprofit;}
};

结果是超时了。

重新寻找另外的思路,

思路还是类似的,不过转而采用动态规划。

class Solution {
public:int memo[50001];int findMaxProfit(vector<vector<int>>& jobs, vector<int>& start, int n, int position) {if (position == n) {return 0;}if (memo[position] != -1) {return memo[position];}int nextIndex = lower_bound(start.begin(), start.end(), jobs[position][1]) - start.begin();int maxProfit = max(findMaxProfit(jobs, start, n, position+1),jobs[position][2] + findMaxProfit(jobs, start, n, nextIndex));return memo[position] = maxProfit;}int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {vector<vector<int>> jobs;memset(memo, -1, sizeof(memo));for (int i = 0; i < profit.size(); ++i) {jobs.push_back({startTime[i], endTime[i], profit[i]});}sort(jobs.begin(), jobs.end());for (int i = 0; i < profit.size(); ++i) {startTime[i] = jobs[i][0];}return findMaxProfit(jobs, startTime, profit.size(), 0);}
};

状态转移方程

  • maxProfit = max(findMaxProfit(..., position+1), jobs[position][2] + findMaxProfit(..., nextIndex))
  • 这个方程表示当前最大利润是两种选择中的较大值:要么跳过当前工作(只考虑下一个工作,即position+1),要么选择当前工作(当前工作的利润加上从nextIndex开始的后续工作的最大利润)。

复杂度分析

  • 时间复杂度:排序工作的时间复杂度为O(n log n)。记忆化搜索的时间复杂度大约为O(n),因为每个工作最多被考虑一次。因此,总的时间复杂度大约为O(n log n)。
  • 空间复杂度:主要由记忆化数组memo和工作数组jobs决定,这两者的空间复杂度都是O(n)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/329526.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】几种常用的类型转换

类型转换 c语言中的类型转换C的类型转换static_castreinterpret_castconst_castdynamic_cast c语言中的类型转换 在C语言中我们经常会遇到类型转化的问题&#xff0c;主要分为两种&#xff1a;显式类型转换和隐式类型转换。 显式类型转换&#xff1a;就是程序员使用强制类型转…

Kali Linux——设置中文

【问题现象】 从下图可以看到&#xff0c;菜单全是英文的。对于英文不好的同学&#xff0c;使用起来很难受。 【解决方法】 1、获取root权限 su root 2、进入语言设置 dpkg-reconfigure locales 3、选择zh_CN.UTF-8 UTF-8 4、设置默认 5、安装完成 6、重启虚拟机 reboot…

关于java的多维数组

关于java的多维数组 在前面的文章中&#xff0c;我们了解了数组的使用&#xff0c;我们之前所了解的数组是一维数组&#xff0c;本篇文章我们来了解一下二维数组&#xff0c;多维数组&#x1f600; 一、二维数组 首先我们知道一维数组的声明和创建的方式是。 int array ne…

Mysql SQL审核平台Yearning本地部署

文章目录 前言1. Linux 部署Yearning2. 本地访问Yearning3. Linux 安装cpolar4. 配置Yearning公网访问地址5. 公网远程访问Yearning管理界面6. 固定Yearning公网地址 前言 Yearning 简单, 高效的MYSQL 审计平台 一款MYSQL SQL语句/查询审计工具&#xff0c;为DBA与开发人员使用…

Python和Java环境搭建

小白搭建全流程 首先不建议装在C盘&#xff0c;一旦重置电脑&#xff0c;之前安装第三方包需要重新安装 relolver :解释器 1、Python解释器安装 资源包&#xff1a; 1、 python -version java -version–用于查看是否安装 where python whrer java–用于查看安装的位置【非常…

【强力推荐】GitCode AI开源搜索,面向开发者的专业AI搜索

一、GitCode AI开源搜索是什么&#xff1f; GitCode AI开源搜索 是面开发者的 AI 开源搜索工具&#xff0c;目的是为了帮助开发者快速寻找开源项目代码、解决开发问题和快速寻找答案&#xff0c;帮助开发者提升效率的同时利用代码仓托管能力建立自己个人知识库。 二、GitCode…

yolo 分割label格式标注信息图片显示可视化查看

参考: https://github.com/ultralytics/ultralytics/issues/3137 https://blog.csdn.net/weixin_42357472/article/details/135218349?spm=1001.2014.3001.5501 需要把坐标信息在图片上显示 代码 1)只画出了坐标边缘 import cv2 import numpy as np from random impor…

从新手到大师:四大编程范式解锁你的编码力!

编程&#xff0c;就是用代码跟计算机交流&#xff0c;告诉它我们想要它做什么。不同的编程范式就是不同的交流方式&#xff0c;每种方式都有自己独特的语法和规则。 今天&#xff0c;我们就来聊聊这四种主要的编程范式&#xff0c;它们分别是命令式、函数式、面向对象和声明式…

基于springboot的sql防注入过滤器

目录 何为SQL注入基于springboot的sql防注入过滤器 回到顶部 何为SQL注入 SQL注入即是指web应用程序对用户输入数据的合法性没有判断或过滤不严&#xff0c;攻击者可以在web应用程序中事先定义好的查询语句的结尾上添加额外的SQL语句&#xff0c;在管理员不知情的情况下实现…

PMP过了就是中级职称?

&#x1f33b;PMP项目管理专业人士认证在全球范围内受到广泛认可&#xff0c;许多人就误以为获得PMP证书就等同于获得中级职称。但是&#xff0c;事实真的如此吗❓ 1️⃣PMP不属于职称认证 ✅PMP证书&#xff1a; 是由美国项目管理协会(PMI)颁发的专业认证&#xff0c;旨在证明…

有趣的前端知识(一)

推荐阅读 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;一&#xff09; 智能化校园&#xff1a;深入探讨云端管理系统设计与实现&#xff08;二&#xff09; 文章目录 推荐阅读HTML简介基础声明HTML标签标题段落注释水平线文本格式化标签超链接图像<i…

FlinkSQL中【FULL OUTER JOIN】使用实例分析(坑)

Flink版本&#xff1a;flink1.14 最近有【FULL OUTER JOIN】场景的实时数据开发需求&#xff0c;想要的结果是&#xff0c;左右表来了数据都下发数据&#xff1b;左表存在的数据&#xff0c;右表进来可以关联下发&#xff08;同样&#xff0c;右表存在的数据&#xff0c;左表进…