问题描述:
问题:鸡窝托斯魅魔的高效陪玩计划
作为鸡窝托斯魅魔,你有 n 个可爱的学生盼着和你玩耍,但你身为 “大忙人”(要处理各种工作),必须用 最少的总时间 满足所有学生的需求。
- 每个学生有专属的「空闲时间区间」
[start, end]:只能在这个时间段内陪他玩(早了学生在写作业,晚了学生要睡觉,学生也得作息规律~); - 每个学生有「最低陪玩时长」
time:你陪他玩的总时间累计必须达到time(可以分段陪,不用一次性连续,但总时长不能少); - 你的关键限制:同一时间可以陪无数个学生玩;
- 你的目标:找到一种陪玩时间安排,让你 投入的总时间最少。
问题转换:
要在一个时间区间内能与最多的学生玩耍(贪心)
- 将每个学生回家的时间按照升序排列。(排序)
- 让每个学生回家的时间尽量晚,便于与其他学生安排在一起。(贪心)
class Solution {
public:
// 场景:安排陪玩时间,用最少总时间满足所有学生需求
int minimumPlayTime(vector<vector<int>>& students) {
// ① 按学生空闲区间的结束时间升序排序(优先陪早结束的学生,避免错过她的空闲时间)
ranges::sort(students, {}, [](auto& cmp) { return cmp[1]; });
int totalPlayTime = 0; // 总陪玩时间(你要投入的最少总时间)
// 时间轴:run[time] = 1 表示这个时间点正在陪学生玩
vector<int> run(students.back()[1] + 1);
for (auto& student : students) {
int freeStart = student[0]; // 学生空闲开始时间
int freeEnd = student[1]; // 学生空闲结束时间
int needPlay = student[2]; // 学生需要的最低陪玩时长
// 计算已重叠的陪玩时间:这个学生的空闲区间内,你已经在陪别人玩的时间(可复用)
needPlay -= reduce(run.begin() + freeStart, run.begin() + freeEnd + 1);
// ② 还有需要补充的陪玩时间:从学生空闲结束时间往前安排(最大化后续重叠)
while (needPlay > 0) {
if (!run[freeEnd]) { // 这个时间点还没安排陪玩
run[freeEnd] = 1; // 标记为正在陪玩
needPlay--; // 剩余需要的陪玩时长减少
totalPlayTime++; // 总陪玩时间增加
}
freeEnd--; // 往前找未安排的时间点
}
}
return totalPlayTime;
}
};
时间复杂度 ;
空间复杂度 ;
力扣题源
2589. 完成所有任务的最少时间 - 力扣(LeetCode)
// 题目总结:在一个区间内执行的任务最多 任务执行的重叠度最高
// ① 排序: 按照任务结束时间升序排序。
// ② 贪心: 让每个任务都尽可能的结束的晚 这样下一个任务与当前任务会有更多的重叠时间。
class Solution {
public:
int findMinimumTime(vector<vector<int>>& tasks) {
ranges::sort(tasks, {}, [](auto& cmp) {return cmp[1];}); // ① 按照end排序
int ans = 0;
vector<int> run(tasks.back()[1] + 1);
for (auto& task : tasks) {
int start = task[0], end = task[1], time = task[2];
// 另外所需的执行时间 = 总的花费时间 - 重叠的时间区域(我和其他任务一起执行)
time -= reduce(run.begin() + start, run.begin() + end + 1);
// 存在另外花费的时间 ② 我就从结束时间开始往前执行
while (time > 0) {
if(!run[end]) {
run[end] = 1; // 标记这个时间已经在执行了(便于前面重叠区域的计算)
time--;
ans++; // 另外花费的时间
}
end--;
}
}
return ans;
}
};
思考:这个算法还能怎么优化?
tips:栈 + 二分
1万+

被折叠的 条评论
为什么被折叠?



