Closed azl397985856 closed 1 year ago
# time; O(nlogn) for sorting and pushing and poping to a pq with max size of n
# space: O(n), for pq
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
sorted_tasks = []
for i, task in enumerate(tasks):
sorted_tasks.append((task[0], task[1], i))
sorted_tasks.sort()
time = sorted_tasks[0][0]
pq = []
res = []
i = 0
while len(res) < len(sorted_tasks):
while i < len(sorted_tasks) and time >= sorted_tasks[i][0]:
heapq.heappush(pq, (sorted_tasks[i][1], sorted_tasks[i][2]))
i += 1
if pq:
next_process, next_index = heapq.heappop(pq)
res.append(next_index)
time += next_process
# no tasks in the pq, skip to next available
elif i < len(sorted_tasks):
time = sorted_tasks[i][0]
return res
public int[] getOrder(int[][] tasks) {
int[] res = new int[tasks.length];
int k=0;
HashMap<int[],Integer> tasksByOrder = new HashMap();
//minheap by starttime
PriorityQueue<int[]> minHeapByStartTime = new PriorityQueue<>((a,b)-> {
return a[0]-b[0];
});
//tasks to hashmap
for(int i=0;i<tasks.length;i++) {
tasksByOrder.put(tasks[i], i);
minHeapByStartTime.add(tasks[i]);
}
PriorityQueue<int[]> minHeapByProcTime = new PriorityQueue<>((a,b)-> {
if(a[1]!=b[1])
return a[1]-b[1];
else
return tasksByOrder.get(a)-tasksByOrder.get(b);
});
int currentTime=minHeapByStartTime.peek()[0];
while(minHeapByStartTime.size()>0 || minHeapByProcTime.size()>0){
//get avail tasks
while(minHeapByStartTime.size()>0 && minHeapByStartTime.peek()[0]<=currentTime)
minHeapByProcTime.add(minHeapByStartTime.poll()); //minheap by minimum processing time
if(minHeapByProcTime.size()==0 && minHeapByStartTime.size()>0)
minHeapByProcTime.add(minHeapByStartTime.poll());
//poll the task and add to "res"
int[] temp = minHeapByProcTime.poll();
res[k++] = (tasksByOrder.get(temp));
currentTime+=temp[1];
}
return res;
}
class Solution(object):
def getOrder(self, tasks):
"""
:type tasks: List[List[int]]
:rtype: List[int]
"""
for i in range(len(tasks)):
tasks[i].append(i)
tasks.sort()
pq = []
heapq.heapify(pq)
curTime = 0
i = 0
taskLeft = len(tasks)
res = []
while i < len(tasks) or pq:
if not pq and tasks[i][0] > curTime:
curTime = tasks[i][0]
while i < len(tasks) and tasks[i][0] <= curTime:
taskTime, taskDur, taskInd = tasks[i]
heapq.heappush(pq, (taskDur, taskInd))
i += 1
newDur, newInd = heapq.heappop(pq)
res.append(newInd)
curTime += newDur
return res
// T: O(nlogn) 排序
// S: O(N)
// 优先队列 q - 等待队列
// 维护一个 now 指针,在 tasks[i][0] <= now 时,将每个任务加入q中
// cpu - 执行任务
class Solution {
public int[] getOrder(int[][] tasks) {
int n = tasks.length;
int[][] tasksWithIds = new int[n][3];
// task[0] 入队时间 | task[1] 执行时间 | task[2] 任务 id
for (int k = 0; k < n; k++) tasksWithIds[k] = new int[]{tasks[k][0], tasks[k][1], k};
Arrays.sort(tasksWithIds, (a, b) -> a[0] - b[0]);
PriorityQueue<int[]> waitingList = new PriorityQueue<>((a, b) -> {
if (a[1] != b[1]) return a[1] - b[1]; // 持续时间不同,返回小的
return a[2] - b[2]; // 持续时间相同,返回时间早的
});
int[] cpu = new int[n];
int i = 0, now = 1;
for (int aIndex = 0; aIndex < n;) {
// 把当前可入队的任务加入等待队列
while (i < n && tasksWithIds[i][0] <= now) {
waitingList.add(tasksWithIds[i++]);
}
if (!waitingList.isEmpty()) {
// 等待队列有任务,从等待队列中(优先队列)取出任务
// cpu 执行任务
// 把 now 指针跳转到任务完成的时候
int [] task = waitingList.poll();
cpu[aIndex++] = task[2]; // 任务id
now += task[1]; // 执行时间
} else {
// 等待队列中没有任务了,now 指针也不要空闲着,直接跳转去下个任务的入队时间
now = tasksWithIds[i][0];
}
}
return cpu;
}
}
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
next_task: List[Tuple[int, int]] = []
tasks_processing_order: List[int] = []
sorted_tasks = [(enqueue, process, idx) for idx, (enqueue, process) in enumerate(tasks)]
sorted_tasks.sort()
curr_time = 0
task_index = 0
while task_index < len(tasks) or next_task:
if not next_task and curr_time < sorted_tasks[task_index][0]:
curr_time = sorted_tasks[task_index][0]
while task_index < len(sorted_tasks) and curr_time >= sorted_tasks[task_index][0]:
_, process_time, original_index = sorted_tasks[task_index]
heapq.heappush(next_task, (process_time, original_index))
task_index += 1
process_time, index = heapq.heappop(next_task)
curr_time += process_time
tasks_processing_order.append(index)
return tasks_processing_order
Priority Queue
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
sorted_task=[]
for i in range(len(tasks)):
sorted_task.append([tasks[i][0],tasks[i][1],i])
sorted_task.sort()
pq=[]
res=[]
i=0
while i < len(sorted_task):
if i < len(sorted_task) and not pq:
cur_time = sorted_task[i][0]
while i<len(sorted_task) and sorted_task[i][0]<=cur_time:
heapq.heappush(pq, (sorted_task[i][1],sorted_task[i][2]))
i+=1
while pq:
t = heappop(pq)
res.append(t[1])
cur_time += t[0]
while i < len(sorted_task) and cur_time >= sorted_task[i][0]:
heappush(pq, (sorted_task[i][1], sorted_task[i][2]))
i += 1
return res
时间复杂度: O(NlogN) 空间复杂度: O(N)
PQ 模拟
Code
class Solution { public int[] getOrder(int[][] tasks) { int n = tasks.length; int[] ans = new int[n]; int[][] extTasks = new int[n][3]; for(int i = 0; i < n; i++) { extTasks[i][0] = i; extTasks[i][1] = tasks[i][0]; extTasks[i][2] = tasks[i][1]; } Arrays.sort(extTasks, (a,b)->a[1] - b[1]); PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> a[2] == b[2] ? a[0] - b[0] : a[2] - b[2]); int time = 0; int ai = 0; int ti = 0; while(ai < n) { while(ti < n && extTasks[ti][1] <= time) { pq.offer(extTasks[ti++]);
}
if(pq.isEmpty()) {
time = extTasks[ti][1];
continue;
}
int[] bestFit = pq.poll();
ans[ai++] = bestFit[0];
time += bestFit[2];
}
return ans;
}
}
- 思路描述:先开始不明白,仔细看就清楚了
#代码
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
tasks = [(task[0], i, task[1]) for i, task in enumerate(tasks)]
tasks.sort()
backlog = []
time = 0
ans = []
pos = 0
for _ in tasks:
if not backlog:
time = max(time, tasks[pos][0])
while pos < len(tasks) and tasks[pos][0] <= time:
heapq.heappush(backlog, (tasks[pos][2], tasks[pos][1]))
pos += 1
d, j = heapq.heappop(backlog)
time += d
ans.append(j)
return ans
- 时间复杂度: O(N*log(N))
- 空间复杂度: O(N)
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
import heapq
n = len(tasks)
indices = list(range(n)).sort(lambda i: tasks[i][0])
ptr = 0
i = 0
q = []
res = []
while(i<n):
if not q:
i = max(i, tasks[indices[ptr]][0])
while i<n and tasks[indices[ptr]][0] <= i:
heapq.heappush(q, (tasks[indices[ptr]][1], indices[ptr]))
ptr+=1
target, idx = heapq.heappop(q)
i += target
res.append(indices[ptr])
return res
class Solution {
public int[] getOrder(int[][] ts) {
int n = ts.length;
// 将 ts 转存成 nts,保留任务编号
int[][] nts = new int[n][3];
for (int i = 0; i < n; i++) nts[i] = new int[]{ts[i][0], ts[i][1], i};
// 根据任务入队时间进行排序
Arrays.sort(nts, (a,b)->a[0]-b[0]);
// 根据题意,先按照「持续时间」排序,再根据「任务编号」排序
PriorityQueue<int[]> q = new PriorityQueue<>((a,b)->{
if (a[1] != b[1]) return a[1] - b[1];
return a[2] - b[2];
});
int[] ans = new int[n];
for (int time = 1, j = 0, idx = 0; idx < n; ) {
// 如果当前任务可以添加到「队列」中(满足入队时间)则进行入队
while (j < n && nts[j][0] <= time) q.add(nts[j++]);
if (q.isEmpty()) {
// 如果当前「队列」没有任务,直接跳到下个任务的入队时间
time = nts[j][0];
} else {
// 如果有可执行任务的话,根据优先级将任务出队(记录下标),并跳到该任务完成时间点
int[] cur = q.poll();
ans[idx++] = cur[2];
time += cur[1];
}
}
return ans;
}
}
from collections import namedtuple
from unittest import result
class Solution:
def getOrder(self,tasks):
Task = namedtuple('Task',['etime','ptime','index'])
stasks = sorted([Task(task[0], task[1], i) for i, task in enumerate(tasks)])
t = i = 0
heap,result = [],[]
while len(result) < len(stasks):
while i < len(stasks) and stasks[i].etime <= t:
heappush(heap, (stasks[i].ptime, stasks[i].index))
i += 1
if heap:
ptime, index = heappop(heap)
result.append(index)
t += ptime
else:
t = stasks[i].etime
return result
code
class Solution {
public int[] getOrder(int[][] tasks) {
// Sort based on min task processing time or min task index.
// Store enqueue time, processing time, task index.
PriorityQueue<int[]> nextTask = new PriorityQueue<int[]>((a, b) -> (a[1] != b[1] ? (a[1] - b[1]) : (a[2] - b[2])));
// Store task enqueue time, processing time, index.
int sortedTasks[][] = new int[tasks.length][3];
for (int i = 0; i < tasks.length; ++i) {
sortedTasks[i][0] = tasks[i][0];
sortedTasks[i][1] = tasks[i][1];
sortedTasks[i][2] = i;
}
Arrays.sort(sortedTasks, (a, b) -> Integer.compare(a[0], b[0]));
int tasksProcessingOrder[] = new int[tasks.length];
long currTime = 0;
int taskIndex = 0;
int ansIndex = 0;
// Stop when no tasks are left in array and heap.
while (taskIndex < tasks.length || !nextTask.isEmpty()) {
if (nextTask.isEmpty() && currTime < sortedTasks[taskIndex][0]) {
// When the heap is empty, try updating currTime to next task's enqueue time.
currTime = sortedTasks[taskIndex][0];
}
// Push all the tasks whose enqueueTime <= currtTime into the heap.
while (taskIndex < tasks.length && currTime >= sortedTasks[taskIndex][0]) {
nextTask.add(sortedTasks[taskIndex]);
++taskIndex;
}
int processTime = nextTask.peek()[1];
int index = nextTask.peek()[2];
nextTask.remove();
// Complete this task and increment currTime.
currTime += processTime;
tasksProcessingOrder[ansIndex++] = index;
}
return tasksProcessingOrder;
}
}
class Solution { public int[] getOrder(int[][] ts) { int n = ts.length; // 将 ts 转存成 nts,保留任务编号 int[][] nts = new int[n][3]; for (int i = 0; i < n; i++) nts[i] = new int[]{ts[i][0], ts[i][1], i}; // 根据任务入队时间进行排序 Arrays.sort(nts, (a,b)->a[0]-b[0]); // 根据题意,先按照「持续时间」排序,再根据「任务编号」排序 PriorityQueue<int[]> q = new PriorityQueue<>((a,b)->{ if (a[1] != b[1]) return a[1] - b[1]; return a[2] - b[2]; }); int[] ans = new int[n]; for (int time = 1, j = 0, idx = 0; idx < n; ) { // 如果当前任务可以添加到「队列」中(满足入队时间)则进行入队 while (j < n && nts[j][0] <= time) q.add(nts[j++]); if (q.isEmpty()) { // 如果当前「队列」没有任务,直接跳到下个任务的入队时间 time = nts[j][0]; } else { // 如果有可执行任务的话,根据优先级将任务出队(记录下标),并跳到该任务完成时间点 int[] cur = q.poll(); ans[idx++] = cur[2]; time += cur[1]; } } return ans; } }
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
n = len(tasks)
indices = list(range(n))
indices.sort(key=lambda x: tasks[x][0])
ans = list()
q = list()
timestamp = 0
ptr = 0
for i in range(n):
if not q:
timestamp = max(timestamp, tasks[indices[ptr]][0])
while ptr < n and tasks[indices[ptr]][0] <= timestamp:
heapq.heappush(q, (tasks[indices[ptr]][1], indices[ptr]))
ptr += 1
process, index = heapq.heappop(q)
timestamp += process
ans.append(index)
return ans
两个优先队列,分别对开始时间和执行时间进行排序
class Solution {
public:
vector<int> getOrder(vector<vector<int>>& tasks) {
//两个优先队列
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<pair<int,int>>>entry,ready;
vector<int>res;
//entry队列,按照进入时间
for(int i=0;i<tasks.size();i++){
entry.push(make_pair(tasks[i][0],i));
}
long now=0;//时间戳变量
while(!entry.empty() || !ready.empty()){
if(ready.empty()){
now=entry.top().first;
while(!entry.empty() && now == entry.top().first){
ready.push(make_pair(tasks[entry.top().second][1],entry.top().second));
entry.pop();
}
}
//ready不为空
now+=ready.top().first;
res.push_back(ready.top().second);
ready.pop();
while(!entry.empty() && now >= entry.top().first){
ready.push(make_pair(tasks[entry.top().second][1],entry.top().second));
entry.pop();
}
}
return res;
}
};
两个队列A、B。A控制CPU处理任务,B控制任务进入A的时机。
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
producer_queue = []
for index in range(len(tasks)):
enqueue_time, processing_time = tasks[index]
heappush(producer_queue, (enqueue_time, processing_time, index))
consumer_queue = []
current_time = -1
result = []
while producer_queue or consumer_queue:
while producer_queue and (not consumer_queue or producer_queue[0][0] <= current_time):
enqueue_time, processing_time, index = heappop(producer_queue)
heappush(consumer_queue, (processing_time, index, enqueue_time))
if consumer_queue:
processing_time, index, enqueue_time = heappop(consumer_queue)
current_time = max(current_time, enqueue_time)
current_time += processing_time
result.append(index)
return result
N = tasks.length
-链接
#include <iostream>
#include <vector>
#include <queue>
using std::vector;
class Solution {
public:
vector<int> getOrder(vector<vector<int>>& tasks) {
// 题目要求,cpu运行为空时,进入时间优先,否则,运行时间优先
// 因此,创建两个优先队列,以最小堆的形式,取出最先/最短时间的任务
// 然后返回执行结果即可
// 创建准备最小堆和进入最小堆
std::priority_queue<
std::pair<int, int>,
std::vector<std::pair<int, int>>,
std::greater<std::pair<int, int>>
> prepare, entry;
// 创建执行结果数组
std::vector<int> execute(tasks.size(), 0);
// 填充准备队列,保存进入时间和索引
for (int idx = 0; idx < tasks.size(); ++idx) {
prepare.emplace(std::pair<int, int>(tasks[idx][0], idx));
}
// 开始准备执行
// 记录当前时间
long now = 0; // 这个时间后期有溢出,所以要换成long
// int temp_idx = 0;
int index = 0;
while(!prepare.empty() || !entry.empty()) {
// 如果当前没有任务正在执行
if (entry.empty()) {
now = prepare.top().first;
// 遍历prepare队列,看看是否有和他进入时间一样的索引
while(!prepare.empty() && now == prepare.top().first) {
// 将需要执行的时间和索引加入 进入队列
entry.emplace(std::pair<int, int>(
tasks[prepare.top().second][1], prepare.top().second));
prepare.pop();
}
}
// 当前entry不为空了,可以正式执行了,取最短执行时间的任务进入执行
execute[index] = entry.top().second;
index++;
// 时间加上执行时间
now += entry.top().first;
entry.pop();
// 将其它进入时间小于now的任务加上entry队列
while(!prepare.empty() && prepare.top().first <= now) {
// 将需要执行的时间和索引加入 进入队列
entry.emplace(std::pair<int, int>(
tasks[prepare.top().second][1], prepare.top().second));
prepare.pop();
}
}
return std::move(execute);
}
};
int main() {
std::vector<std::vector<int>> tasks({{1,2},{2,4},{3,2},{4,1}});
Solution s;
std::vector<int> res = s.getOrder(tasks);
for (const auto x: res) {
std::cout << x << " ";
}
std::cout << std::endl;
}
class Solution { public int[] getOrder(int[][] tasks) { int n = tasks.length;
ArrayList<int[]> triples = new ArrayList<>();
for (int i = 0; i < tasks.length; i++) {
triples.add(new int[]{tasks[i][0], tasks[i][1], i});
}
triples.sort((a, b) -> {
return a[0] - b[0];
});
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> {
if (a[1] != b[1]) {
return a[1] - b[1];
}
return a[2] - b[2];
});
ArrayList<Integer> res = new ArrayList<>();
int now = 0;
int i = 0;
while (res.size() < n) {
if (!pq.isEmpty()) {
int[] triple = pq.poll();
res.add(triple[2]);
now += triple[1];
} else if (i < n && triples.get(i)[0] > now) {
now = triples.get(i)[0];
}
for (; i < n && triples.get(i)[0] <= now; i++) {
pq.offer(triples.get(i));
}
}
int[] arr = new int[n];
for (int j = 0; j < n; j++) {
arr[j] = res.get(j);
}
return arr;
}
}
/***
Solution:
1. stimulation
2. sort tasks by their enqueue time first, (Do not need to use queue)
3. push available task into heap
TIP:
1. use pair<int,int>, save struct, cmp
2. iota == python range
3. emplace pair into queue
4. auto [a, b] = pair to get pair
5. time has to be long long
Time: O(n)
Space: O(n)
***/
class Solution {
using PR = pair<int,int>;
public:
vector<int> getOrder(vector<vector<int>>& tasks) {
vector<int> result;
int n = tasks.size();
vector<int> indices(n);
iota(indices.begin(), indices.end(), 0);
sort(indices.begin(), indices.end(), [&](int i, int j) {
return tasks[i][0] < tasks[j][0];
});
priority_queue<PR, vector<PR>, greater<PR>> pq;
long long time = 0;
int next = 0;
for (int i = 0; i < n; ++i) {
if (pq.empty()) {
// cout << "next" << next << endl;
time = max(time, (long long)tasks[indices[next]][0]);
// cout << "1]" << endl;
}
// cout << "time" <<time << endl;
while (next < n) {
if (tasks[indices[next]][0] <= time) {
// cout << "push idx " << indices[next] << endl;
pq.emplace(tasks[indices[next]][1], indices[next]);
// cout << "push suc " << indices[next] << endl;
}
else {
break;
}
++next;
}
// auto [process_time, id] = pq.top();
auto [process_time, id] = pq.top();
pq.pop();
result.push_back(id);
time += process_time;
// cout << "process" <<process_time << "id" << id << endl;
}
// priority_queue<int> myqueue;
// myqueue.push(1);
// myqueue.push(2);
// myqueue.push(3);
// for (int i = 0; i < 3; ++i) {
// // auto && [n,l] = pair<int,int>(i, i);
// auto && n = myqueue.top();
// auto l = myqueue.top();
// myqueue.pop();
// cout << "n " << n << "l " << l << endl;
// }
return result;
}
};
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
import heapq
tasks_list = [(i, task[0] ,task[1]) for i, task in enumerate(tasks)]
tasks_list = sorted(tasks_list, key = lambda x: (x[1],x[0]))
backlog = []
time = 0
ans = []
pos = 0
process
for _ in tasks_list:
if not backlog:
time = max(time, tasks[pos][1])
while pos < len(tasks) and tasks_list[pos][1]< time:
heapq.heappush(backlog ,(tasks_list[pos][2], tasks_list[pos][0]))
pos += 1
delta_time, index = heapq.heappop(backlog)
time += delta_time
ans.append(index)
return ans
时间复杂度:O(nlogn) 空间复杂度:O(n)
const getOrder = function (tasks) {
const queue = new MinPriorityQueue();
tasks = tasks.map((task, index) => ({
index,
start: task[0],
time: task[1],
}));
tasks.sort((a, b) => b.start - a.start);
const answer = [];
let time = 0;
while (tasks.length > 0 || !queue.isEmpty()) {
// 队列为空,且没有任务能加入队列,直接跳过时间
if (queue.isEmpty() && tasks[tasks.length - 1].start > time) {
time = tasks[tasks.length - 1].start;
}
// 向队列中加入可执行任务
while (tasks.length > 0) {
if (tasks[tasks.length - 1].start <= time) {
const task = tasks.pop();
queue.enqueue(task, task.time * 100000 + task.index);
} else {
break;
}
}
// 执行任务
const { element: task } = queue.dequeue();
time += task.time;
answer.push(task.index);
}
return answer;
};
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
n = len(tasks)
sorted_idxs = sorted([*range(n)], key = lambda x: tasks[x][0])
i = 0
queue = []
timestamp = 0
ans = []
while i < n or queue:
if not queue and timestamp < tasks[sorted_idxs[i]][0]:
timestamp = tasks[sorted_idxs[i]][0]
while i< n and tasks[sorted_idxs[i]][0] <= timestamp:
heapq.heappush(queue, (tasks[sorted_idxs[i]][1], sorted_idxs[i]))
i += 1
process_time, idx = heapq.heappop(queue)
timestamp += process_time
ans.append(idx)
return ans
Heap
class Solution {
public int[] getOrder(int[][] tasks) {
int n = tasks.length;
int[] res = new int[n];
int[][] tri = new int[n][3];
for(int i = 0; i < n; i++) {
tri[i][0] = i;
tri[i][1] = tasks[i][0];
tri[i][2] = tasks[i][1];
}
Arrays.sort(tri, (a,b)-> a[1] - b[1]);
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[2] == b[2] ? a[0] - b[0] : a[2] - b[2]);
int time = 0;
int i = 0, j = 0;
while(j < n) {
while(i < n && tri[i][1] <= time) {
pq.offer(tri[i++]);
}
if(pq.isEmpty()) {
time = tri[i][1];
continue;
} else {
int[] task = pq.poll();
res[j++] = task[0];
time += task[2];
}
}
return res;
}
}
Complexity Analysis
排序+优先队列
const getOrder = function (tasks) {
const queue = new MinPriorityQueue()
tasks = tasks.map((task, index) => ({
index,
start: task[0],
time: task[1]
}))
tasks.sort((a, b) => b.start - a.start)
const answer = []
let time = 0
while (tasks.length > 0 || !queue.isEmpty()) {
if (queue.isEmpty() && tasks[tasks.length - 1].start > time) {
time = tasks[tasks.length - 1].start
}
while (tasks.length > 0) {
if (tasks[tasks.length -1].start <= time) {
const task = tasks.pop()
queue.enqueue(task, task.time * 100000 + task.index)
} else {
break
}
}
const { element: task } = queue.dequeue()
time += task.time
answer.push(task.index)
}
return answer
}
func getOrder(tasks [][]int) []int {
res := make([]int, 0)
pq := make(PQ, 0)
t := make([]*Task, 0)
for i := 0; i < len(tasks); i++ {
t = append(t, &Task{i, tasks[i][0], tasks[i][1]})
}
// sort Task slice by enqueue time
sort.Slice(t, func(i, j int) bool {
return t[i].enqueueTime < t[j].enqueueTime
})
curTime := t[0].enqueueTime
nextTime := t[0].enqueueTime
index := 0
for index < len(t) {
// enqueue all the tasks within current enqueue time
for index < len(t) && t[index].enqueueTime <= curTime {
heap.Push(&pq, t[index])
index++
}
// pop out all the ones meet the criteria, they need to be less than the next one in the Task array
// we need to update the enqueueTime every time we pop out one task, so we don't miss any coming tasks
for len(pq) > 0 && index < len(t) && nextTime < t[index].enqueueTime {
cur := heap.Pop(&pq).(*Task)
res = append(res, cur.index)
nextTime += cur.processingTime
}
// this is important, if next enqueue time is way bigger than the current time, we will stuck in the loop
// eg [[1,1],[20,20]]
if index < len(t) {
nextTime = max(nextTime, t[index].enqueueTime)
}
curTime = nextTime
}
// add the rest
for len(pq) > 0 {
cur := heap.Pop(&pq).(*Task)
res = append(res, cur.index)
}
return res
}
func max(i, j int) int {
if i > j {
return i
}
return j
}
type Task struct {
index int
enqueueTime int
processingTime int
}
type PQ []*Task
func (this PQ) Len() int {
return len(this)
}
func (this PQ) Less(i, j int) bool {
if this[i].processingTime == this[j].processingTime {
return this[i].index < this[j].index
} else {
return this[i].processingTime < this[j].processingTime
}
}
func (this PQ) Swap(i, j int) {
this[i], this[j] = this[j], this[i]
}
func (this *PQ) Push(p interface{}) {
*this = append(*this, p.(*Task))
}
func (this *PQ) Pop() interface{} {
p := (*this)[len(*this)-1]
*this = (*this)[:len(*this)-1]
return p
}
class Solution {
public int[] getOrder(int[][] tasks) {
int n = tasks.length;
int[] ans = new int[n];
int[][] extTasks = new int[n][3];
for(int i = 0; i < n; i++) {
extTasks[i][0] = i;
extTasks[i][1] = tasks[i][0];
extTasks[i][2] = tasks[i][1];
}
Arrays.sort(extTasks, (a,b)->a[1] - b[1]);
PriorityQueue<int[]> pq = new PriorityQueue<int[]>((a, b) -> a[2] == b[2] ? a[0] - b[0] : a[2] - b[2]);
int time = 0;
int ai = 0;
int ti = 0;
while(ai < n) {
while(ti < n && extTasks[ti][1] <= time) {
pq.offer(extTasks[ti++]);
}
if(pq.isEmpty()) {
time = extTasks[ti][1];
continue;
}
int[] bestFit = pq.poll();
ans[ai++] = bestFit[0];
time += bestFit[2];
}
return ans;
}
}
使用两个数据结构,一个数组保存节点下标,并且根据入队列时间排序,另外使用一个小顶堆,保存当前队列中的任务,每次弹出堆定的元素进行执行,按照上述思路进行模拟。
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
order = []
n = len(tasks)
idx = list(range(n))
idx.sort(key=lambda x: tasks[x][0])
p = 0
t = 0
queue = []
while p < n or queue:
if not queue and t < tasks[idx[p]][0]:
t = tasks[idx[p]][0]
while p < n and tasks[idx[p]][0] <= t:
heapq.heappush(queue, (tasks[idx[p]][1], idx[p]))
p += 1
process_time, i = heapq.heappop(queue)
t += process_time
order.append(i)
return order
通过题解学习
按照题目情况进行模拟,需要使用新的数组记录任务的id,对任务表按照加入队列的时间排序
创建优先队列,按照执行时间排序
class Solution {
public int[] getOrder(int[][] tasks) {
// tasks 的指针、系统当前时间
int length = tasks.length, point = 0, systemTime = 0, resultPoint = 0;
int result[] = new int[length];
int[][] tasksIds = new int[length][3];
// 为 tasks 添加 id
for (int i = 0; i < tasksIds.length; i++) {
tasksIds[i][0] = tasks[i][0];
tasksIds[i][1] = tasks[i][1];
tasksIds[i][2] = i;
}
// 按照 tasks 的执行时间先后进行排序
Arrays.sort(tasksIds, (a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
// 优先队列,[执行时间][任务id] --> 队列中选择时间最短的任务执行,多个最短时间任务选择下表最小的
PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
while (point < length) {
// 当任务列表中的加入时间小于当前系统时间,就把任务加入到队列中
// 直到当前时间内的任务都添加到队列
while (point < length && tasksIds[point][0] <= systemTime) {
queue.add(new int[]{tasksIds[point][1], tasksIds[point][2]});
point++;
}
if (queue.isEmpty()) {
// 队列为空,跳过执行过程,系统时间赋值为下一个任务的开始时间
systemTime = tasksIds[point][0];
} else {
// 队列不为空,执行任务,把任务id写入到结果中
int[] poll = queue.poll();
result[resultPoint] = poll[1];
systemTime += poll[0];
resultPoint++;
}
}
while (!queue.isEmpty()) {
result[resultPoint++] = queue.poll()[1];
}
return result;
}
}
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
n = len(tasks)
idx = list(range(n))
idx.sort(key=lambda x: tasks[x][0])
ans = []
queue = []
time = 0
ptr = 0
for i in range(n):
if not queue:
time = max(time, tasks[idx[ptr]][0])
while ptr < n and tasks[idx[ptr]][0] <= time:
heapq.heappush(queue, (tasks[idx[ptr]][1], idx[ptr]))
ptr += 1
p, i = heapq.heappop(queue)
time += p
ans.append(i)
return ans
class Solution {
public int[] getOrder(int[][] tasks) {
PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> a[1] == b[1] ? a[2] - b[2] : a[1] - b[1]);
int n = tasks.length;
int[] ans = new int[n];
int[][] sortedTasks = new int[n][3];
for (int i = 0; i < n; i++) {
sortedTasks[i][0] = tasks[i][0];
sortedTasks[i][1] = tasks[i][1];
sortedTasks[i][2] = i;
}
Arrays.sort(sortedTasks, (a, b) -> (a[0] - b[0]));
int task = 0, time = 0, ansIndex = 0;
while (ansIndex < n) {
while (task < n && sortedTasks[task][0] <= time) {
heap.offer(sortedTasks[task++]);
}
if (heap.isEmpty()) {
time = sortedTasks[task][0];
continue;
}
int[] job = heap.poll();
ans[ansIndex++] = job[2];
time += job[1];
}
return ans;
}
}
Time: O(nlgn) Space: O(n)
class Solution {
public int[] getOrder(int[][] tasks) {
Comparator<int[]> availableTasksComparator = new Comparator<int[]>(){
@Override
public int compare(int[] i1, int[] i2){
if(i1[1]!=i2[1]){
return i1[1]-i2[1];
}else{
return i1[2]-i2[2];
}
}
};
PriorityQueue<int[]> availableTasks = new PriorityQueue<>(availableTasksComparator);
int[][] sortedArr = new int[tasks.length][tasks[0].length+1];
for(int i = 0;i<tasks.length;i++){
int[] newArr = new int[]{i};
System.arraycopy(tasks[i], 0, sortedArr[i], 0, tasks[i].length);
System.arraycopy(newArr, 0, sortedArr[i], tasks[i].length, 1);
};
Arrays.sort(sortedArr, new Comparator<int[]>(){
@Override
public int compare(final int[] entry1, final int[] entry2){
final int time1 = entry1[0];
final int time2 = entry2[0];
return time1-time2;
}
});
int currTime = 1;
int taskNum = tasks.length;
int taskIndex = 0;
int[] res = new int[taskNum];
int resIdx = 0;
while(taskIndex<taskNum || !availableTasks.isEmpty()){
if(availableTasks.isEmpty() && currTime<sortedArr[taskIndex][0]){
currTime = sortedArr[taskIndex][0];
}
while(taskIndex<taskNum && currTime>=sortedArr[taskIndex][0]){
availableTasks.add(sortedArr[taskIndex]);
taskIndex++;
}
int[] currTask = availableTasks.poll();
currTime+=currTask[1];
res[resIdx] = currTask[2];
resIdx++;
}
return res;
}
}
Complexity Analysis
/**
* @param {number[][]} tasks
* @return {number[]}
*/
var getOrder = function (tasks) {
const queue = new MinPriorityQueue();
tasks = tasks.map((task, index) => ({
index,
start: task[0],
time: task[1],
}));
tasks.sort((a, b) => b.start - a.start);
const answer = [];
let time = 0;
while (tasks.length > 0 || !queue.isEmpty()) {
// 队列为空,且没有任务能加入队列,直接跳过时间
if (queue.isEmpty() && tasks[tasks.length - 1].start > time) {
time = tasks[tasks.length - 1].start;
}
// 向队列中加入可执行任务
while (tasks.length > 0) {
if (tasks[tasks.length - 1].start <= time) {
const task = tasks.pop();
queue.enqueue(task, task.time * 100000 + task.index);
} else {
break;
}
}
// 执行任务
const { element: task } = queue.dequeue();
time += task.time;
answer.push(task.index);
}
return answer;
}
greater<pair<int, int>>
iota()
范围赋值函数(此题为下标)class Solution {
public:
using LL = long long;
vector<int> getOrder(vector<vector<int>>& tasks) {
int n = tasks.size();
vector<int> indx(n);
iota(indx.begin(), indx.end(), 0); //范围赋值
sort(indx.begin(), indx.end(), [&](int i, int j){
return tasks[i][0] < tasks[j][0];
});//自定义排序
vector<int> res;
priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
LL timeStamps = 0;
int p = 0; //遍历拷贝数组(按照进去队列的时间排序)的指针
for(int i = 0; i < n; i++) {
if(pq.empty()) //任务队列为空,时间戳更新
timeStamps = max(timeStamps, (LL)tasks[indx[p]][0]);
while(p < n && tasks[indx[p]][0] <= timeStamps) { //小于时间戳的任务放到任务队列当中
pq.emplace(tasks[indx[p]][1], indx[p]);
p++;
}
//执行任务
auto [run, index] = pq.top();
timeStamps += run;
pq.pop();
res.push_back(index);
}
return res;
}
};
//最近太忙了,后面看看
class Solution { public int[] getOrder(int[][] ts) { int n = ts.length; int[][] nts = new int[n][3]; for (int i = 0; i < n; i++) nts[i] = new int[]{ts[i][0], ts[i][1], i}; Arrays.sort(nts, (a,b)->a[0]-b[0]); PriorityQueue<int[]> q = new PriorityQueue<>((a,b)->{ if (a[1] != b[1]) return a[1] - b[1]; return a[2] - b[2]; }); int[] ans = new int[n]; for (int time = 1, j = 0, idx = 0; idx < n; ) { while (j < n && nts[j][0] <= time) q.add(nts[j++]); if (q.isEmpty()) { time = nts[j][0]; } else { int[] cur = q.poll(); ans[idx++] = cur[2]; time += cur[1]; } } return ans; } }
优先队列
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
tasks = sorted(enumerate(tasks), key=lambda x: (-x[1][0],-x[1][1],-x[0]))
ans = []
pq = []
time = 0
while tasks or pq:
if pq:
l, idx, t = heapq.heappop(pq)
else:
idx, v = tasks.pop()
t, l = v
ans.append(idx)
time = max(t,time) + l
while tasks and tasks[-1][1][0] <= time:
index, val = tasks.pop()
ti, le = val
heapq.heappush(pq, (le, index, ti))
return ans
给你一个二维数组 tasks ,用于表示项从 0 到 n - 1 编号的任务。其中 tasks[i] = [enqueueTimei, processingTimei] 意味着第 i 项任务将会于 enqueueTimei 时进入任务队列,需要 processingTimei 的时长完成执行。
现有一个单线程 CPU ,同一时间只能执行 最多一项 任务,该 CPU 将会按照下述方式运行:
如果 CPU 空闲,且任务队列中没有需要执行的任务,则 CPU 保持空闲状态。 如果 CPU 空闲,但任务队列中有需要执行的任务,则 CPU 将会选择 执行时间最短 的任务开始执行。如果多个任务具有同样的最短执行时间,则选择下标最小的任务开始执行。 一旦某项任务开始执行,CPU 在 执行完整个任务 前都不会停止。 CPU 可以在完成一项任务后,立即开始执行一项新任务。 返回 CPU 处理任务的顺序。
给CPU分配任务,先按照入CPU时间排序,如果入CPU时间相同的话,按照处理时间索引小的来的进入CPU。
Golang 代码
type pair struct{ t, i int }
type hp []pair
func (h hp) Len() int { return len(h) }
// Less 先按照开始时间排序,如果相同的开始时间的话,按照小的索引来排序
func (h hp) Less(i, j int) bool { a, b := h[i], h[j]; return a.t < b.t || a.t == b.t && a.i < b.i }
// Swap 互换
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
// Push 添加
func (h *hp) Push(v interface{}) { *h = append(*h, v.(pair)) }
// Pop 弹出 一个元素
func (h *hp) Pop() interface{} { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
// 堆添加到
func (h *hp) push(v pair) { heap.Push(h, v) }
// 堆弹出
func (h *hp) pop() pair { return heap.Pop(h).(pair) }
//
// getOrder
// @Description:
// @param a
// @return ans
//
func getOrder(a [][]int) (ans []int) {
for i := range a {
a[i] = append(a[i], i)
}
sort.Slice(a, func(i, j int) bool { return a[i][0] < a[j][0] })
h := &hp{}
for i, cur, n := 0, 0, len(a); i < n; {
// 如果有任务
if h.Len() > 0 {
p := h.pop()
ans = append(ans, p.i)
cur += p.t
}
// 没有任务
if h.Len() == 0 && cur < a[i][0] {
cur = a[i][0]
}
// 完成任务
for ; i < n && a[i][0] <= cur; i++ {
h.push(pair{a[i][1], a[i][2]})
}
}
for h.Len() > 0 {
ans = append(ans, h.pop().i)
}
return
}
复杂度分析
class Solution: def getOrder(self, tasks: List[List[int]]) -> List[int]: n = len(tasks) indices = list(range(n)) indices.sort(key=lambda x: tasks[x][0])
ans = list()
# 优先队列
q = list()
# 时间戳
timestamp = 0
# 数组上遍历的指针
ptr = 0
for i in range(n):
# 如果没有可以执行的任务,直接快进
if not q:
timestamp = max(timestamp, tasks[indices[ptr]][0])
# 将所有小于等于时间戳的任务放入优先队列
while ptr < n and tasks[indices[ptr]][0] <= timestamp:
heapq.heappush(q, (tasks[indices[ptr]][1], indices[ptr]))
ptr += 1
# 选择处理时间最小的任务
process, index = heapq.heappop(q)
timestamp += process
ans.append(index)
return ans
class Solution { public int[] getOrder(int[][] tasks) { int len = tasks.length; int[][] tasksIdx = new int[len][3]; for (int i = 0; i < tasksIdx.length; i++) { tasksIdx[i][0] = tasks[i][0]; tasksIdx[i][1] = tasks[i][1]; tasksIdx[i][2] = i; } Arrays.sort(tasksIdx, (a, b) -> a[0] - b[0]); int time = 0; // int[]{执行时间,index} PriorityQueue<int[]> queue = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); int p = 0; int[] ans = new int[len]; int ansp = 0; while (p < len) { while (p < len && tasksIdx[p][0] <= time) { queue.add(new int[] { tasksIdx[p][1], tasksIdx[p][2] }); p++; } if (queue.isEmpty()) { time = tasksIdx[p][0]; } else { int[] cur = queue.poll(); ans[ansp++] = cur[1]; time += cur[0]; } } while (!queue.isEmpty()) { ans[ansp++] = queue.poll()[1]; } return ans; } }
模拟,time表示时间,ans表示已完成任务列表,pq表示待完成任务列表。
class Solution {
public int[] getOrder(int[][] tasks) {
int[][] nts = new int[tasks.length][3];
for (int i = 0; i < tasks.length; i++) {
nts[i] = new int[] {tasks[i][0], tasks[i][1], i};
}
Arrays.sort(nts, (a, b) -> a[0] - b[0]);
Queue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] == b[1] ? a[2] - b[2] : a[1] - b[1]);
int[] ans = new int[tasks.length];
int time = 1, idx = 0, i = 0;
while (idx < tasks.length) {
while (i < tasks.length && nts[i][0] <= time) {
pq.offer(nts[i++]);
}
if (pq.isEmpty()) {
time = nts[i][0];
} else {
int[] cur = pq.poll();
ans[idx++] = cur[2];
time += cur[1];
}
}
return ans;
}
}
复杂度
Language: Java
class Solution {
public int[] getOrder(int[][] tasks) {
int n = tasks.length;
ArrayList<int[]> triples = new ArrayList<>();
for (int i = 0; i < tasks.length; i++) {
triples.add(new int[]{tasks[i][0], tasks[i][1], i});
}
triples.sort((a, b) -> {
return a[0] - b[0];
});
PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> {
return a[1] == b[1] ? a[2] - b[2] : a[1] - b[1];
});
ArrayList<Integer> res = new ArrayList<>();
int now = 0;
int i = 0;
while (res.size() < n) {
if (!pq.isEmpty()) {
int[] triple = pq.poll();
res.add(triple[2]);
now += triple[1];
} else if (i < n && triples.get(i)[0] > now) {
now = triples.get(i)[0];
}
while (i < n && triples.get(i)[0] <= now) {
pq.offer(triples.get(i));
i++;
}
}
int[] arr = new int[n];
for (int j = 0; j < n; j++) {
arr[j] = res.get(j);
}
return arr;
}
}
class Solution {
public:
vector<int> getOrder(vector<vector<int>>& tasks) {
// 开始时间,执行时长,下标
priority_queue<pair<int,pair<int,int>>,
vector<pair<int,pair<int,int>>>,
greater<>> q1;
for (int i = 0; i < tasks.size(); ++i) {
q1.push(make_pair(tasks[i][0],make_pair(tasks[i][1],i)));
}
//执行时长,下标
priority_queue<pair<int,int>,vector<pair<int,int>>,greater<>> q2;
long t =0;
vector<int> ans;
while (!q1.empty()||!q2.empty()){
while (!q1.empty()&&q1.top().first<=t){
q2.push(q1.top().second);
q1.pop();
}
if(q2.empty()){
t = q1.top().first;
continue;
}
auto task = q2.top();
q2.pop();
ans.push_back(task.second);
t+= task.first;
}
return ans;
}
};
有一个特殊的情况,任务队列中所有任务的时入时间均小于第1步中计算得到的当前时间,那么,为了能够将流程推进下去, 应该将当前时间再继续往前推进到剩下的任务中最早进入的那个时间
func getOrder(tasks [][]int) []int {
var ret []int
var newTasks = make([]*taskMeta, 0, len(tasks))
for idx, item := range tasks {
newTasks = append(newTasks, &taskMeta{
idx: idx,
time: item,
})
}
sort.Slice(newTasks, func(i, j int) bool {
if newTasks[i].time[0] < newTasks[j].time[0] {
return true
}
if newTasks[i].time[0] > newTasks[j].time[0] {
return false
}
if i < j {
return true
}
return false
})
taskIdx := 0
curTime := newTasks[0].time[0]
heap := newMyHeap()
for ; taskIdx < len(newTasks); taskIdx++ {
if curTime != newTasks[taskIdx].time[0] {
break
}
heap.push(&taskMeta{idx: newTasks[taskIdx].idx, time: newTasks[taskIdx].time})
}
for heap.len() != 0 {
cur := heap.delete()
ret = append(ret, cur.idx)
curTime += cur.time[1]
found := false
for ; taskIdx < len(newTasks); taskIdx++ {
if newTasks[taskIdx].time[0] <= curTime {
heap.push(&taskMeta{idx: newTasks[taskIdx].idx, time: newTasks[taskIdx].time})
found = true
continue
}
break
}
if !found && taskIdx != len(newTasks) && heap.len() == 0 {
// CPU空闲时间
curTime = newTasks[taskIdx].time[0]
for ; taskIdx < len(newTasks); taskIdx++ {
if curTime != newTasks[taskIdx].time[0] {
break
}
heap.push(&taskMeta{idx: newTasks[taskIdx].idx, time: newTasks[taskIdx].time})
}
}
}
return ret
}
type taskMeta struct {
idx int
time []int
}
type myHeap struct {
data []*taskMeta
}
func newMyHeap() *myHeap {
return &myHeap{data: make([]*taskMeta, 0)}
}
func (h *myHeap) push(v *taskMeta) {
h.data = append(h.data, v)
h.up()
}
func (h *myHeap) delete() *taskMeta {
tmp := h.data[0]
h.swap(0, h.len() - 1)
h.data = h.data[:h.len() - 1]
h.down(0)
return tmp
}
func (h *myHeap) up() {
last := h.len() - 1
for {
parent := h.getParent(last)
if parent == -1 {
break
}
if !h.less(last, parent) {
break
}
h.swap(last, parent)
last = parent
}
}
func (h *myHeap) down(b int) {
var maxChildValue func(idx int) int
maxChildValue = func(idx int) int {
leftChild := h.getLeftChild(idx)
rightChild := h.getRightChild(idx)
if rightChild != -1 && leftChild != -1 {
if h.less(leftChild, rightChild) {
return leftChild
}
return rightChild
}
return leftChild
}
for {
child := maxChildValue(b)
if child == -1 {
break
}
if h.less(b, child) {
break
}
h.swap(b, child)
b = child
}
}
func (h *myHeap) getParent(idx int) int {
if idx == 0 {return -1}
return (idx - 1) / 2
}
func (h *myHeap) getLeftChild(idx int) int {
cIdx := 2 * idx + 1
if cIdx >= h.len() {
return -1
}
return cIdx
}
func (h *myHeap) getRightChild(idx int) int {
cIdx := 2 * idx + 2
if cIdx >= h.len() {
return -1
}
return cIdx
}
func (h *myHeap) len() int {
return len(h.data)
}
func (h *myHeap) swap(i, j int) {
h.data[i], h.data[j] = h.data[j], h.data[i]
}
func (h *myHeap) less(i, j int) bool {
if h.data[i].time[1] < h.data[j].time[1] {
return true
}
if h.data[i].time[1] > h.data[j].time[1] {
return false
}
if h.data[i].idx < h.data[j].idx {
return true
}
return false
}
// 先熟悉一下堆,后面再来做这道题
/**
* @param {number[][]} tasks
* @return {number[]}
*/
const getOrder = function (tasks) {
const queue = new MinPriorityQueue();
tasks = tasks.map((task, index) => ({
index,
start: task[0],
time: task[1],
}));
tasks.sort((a, b) => b.start - a.start);
const answer = [];
let time = 0;
while (tasks.length > 0 || !queue.isEmpty()) {
// 队列为空,且没有任务能加入队列,直接跳过时间
if (queue.isEmpty() && tasks[tasks.length - 1].start > time) {
time = tasks[tasks.length - 1].start;
}
// 向队列中加入可执行任务
while (tasks.length > 0) {
if (tasks[tasks.length - 1].start <= time) {
const task = tasks.pop();
queue.enqueue(task, task.time * 100000 + task.index);
} else {
break;
}
}
// 执行任务
const { element: task } = queue.dequeue();
time += task.time;
answer.push(task.index);
}
return answer;
};
- 思路描述
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
n = len(tasks)
indices = list(range(n))
indices.sort(key=lambda x: tasks[x][0])
ans = list()
# 优先队列
q = list()
# 时间戳
timestamp = 0
# 数组上遍历的指针
ptr = 0
for i in range(n):
# 如果没有可以执行的任务,直接快进
if not q:
timestamp = max(timestamp, tasks[indices[ptr]][0])
# 将所有小于等于时间戳的任务放入优先队列
while ptr < n and tasks[indices[ptr]][0] <= timestamp:
heapq.heappush(q, (tasks[indices[ptr]][1], indices[ptr]))
ptr += 1
# 选择处理时间最小的任务
process, index = heapq.heappop(q)
timestamp += process
ans.append(index)
return ans
- 时间复杂度:
- 空间复杂度:
思路: 一个数组存储(enqueue_time,process_time,origin_idx)元素,一个优先队列存储(process_time, origin_idx)。 官方题解简洁易读,mark 一下
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
# Sort based on min task processing time or min task index.
next_task: List[Tuple[int, int]] = []
tasks_processing_order: List[int] = []
# Store task enqueue time, processing time, index.
sorted_tasks = [(enqueue, process, idx) for idx, (enqueue, process) in enumerate(tasks)]
sorted_tasks.sort()
curr_time = 0
task_index = 0
# Stop when no tasks are left in array and heap.
while task_index < len(tasks) or next_task:
if not next_task and curr_time < sorted_tasks[task_index][0]:
# When the heap is empty, try updating curr_time to next task's enqueue time.
curr_time = sorted_tasks[task_index][0]
# Push all the tasks whose enqueueTime <= currtTime into the heap.
while task_index < len(sorted_tasks) and curr_time >= sorted_tasks[task_index][0]:
_, process_time, original_index = sorted_tasks[task_index]
heapq.heappush(next_task, (process_time, original_index))
task_index += 1
process_time, index = heapq.heappop(next_task)
# Complete this task and increment curr_time.
curr_time += process_time
tasks_processing_order.append(index)
return tasks_processing_order
设计一个优先队列(堆),将任务按起始时间排序后,根据当前时间线依次入队,再从队列中根据题目要求取出优先级最高的任务执行,直至完成全部任务。
class Solution {
public int[] getOrder(int[][] tasks) {
int n = tasks.length;
int[] ans = new int[n];//待求的任务处理顺序
PriorityQueue<int[]> toDo = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] a, int[] b) {
if (a[1] != b[1])//注意Integer比较用equals和compareTo
return a[1] - b[1];
return a[2] - b[2];
}
});
int[][] newTasks = new int[n][3];//添加任务序号信息
for (int i = 0; i < n; i++) {
newTasks[i][0] = tasks[i][0];
newTasks[i][1] = tasks[i][1];
newTasks[i][2] = i;
}
Arrays.sort(newTasks, (t1, t2) -> t1[0] - t2[0]);//将任务按时间排序
int t = 0, index = 0, i = 0;//当前时间,已执行任务数,已入队任务数
while (index < n) {
if (toDo.isEmpty())//若队列为空且当前时间小于下一任务起始时间,直接跳到该起始时间
t = Math.max(t, newTasks[i][0]);
while (i < n && newTasks[i][0] <= t)//将起始时间不超过当前时间的任务都入队
toDo.offer(newTasks[i++]);
int[] task = toDo.poll();//选取优先执行的任务
ans[index++] = task[2];
t += task[1];
}
return ans;
}
}
class Solution {
private:
using PII = pair<int, int>;
using LL = long long;
public:
vector<int> getOrder(vector<vector<int>>& tasks) {
int n = tasks.size();
vector<int> indices(n);
iota(indices.begin(), indices.end(), 0);
sort(indices.begin(), indices.end(), [&](int i, int j) {
return tasks[i][0] < tasks[j][0];
});
vector<int> ans;
// 优先队列
priority_queue<PII, vector<PII>, greater<PII>> q;
// 时间戳
LL timestamp = 0;
// 数组上遍历的指针
int ptr = 0;
for (int i = 0; i < n; ++i) {
// 如果没有可以执行的任务,直接快进
if (q.empty()) {
timestamp = max(timestamp, (LL)tasks[indices[ptr]][0]);
}
// 将所有小于等于时间戳的任务放入优先队列
while (ptr < n && tasks[indices[ptr]][0] <= timestamp) {
q.emplace(tasks[indices[ptr]][1], indices[ptr]);
++ptr;
}
// 选择处理时间最小的任务
auto&& [process, index] = q.top();
timestamp += process;
ans.push_back(index);
q.pop();
}
return ans;
}
};
const getOrder = function (tasks) {
const queue = new MinPriorityQueue();
tasks = tasks.map((task, index) => ({
index,
start: task[0],
time: task[1],
}));
tasks.sort((a, b) => b.start - a.start);
const answer = [];
let time = 0;
while (tasks.length > 0 || !queue.isEmpty()) {
// 队列为空,且没有任务能加入队列,直接跳过时间
if (queue.isEmpty() && tasks[tasks.length - 1].start > time) {
time = tasks[tasks.length - 1].start;
}
// 向队列中加入可执行任务
while (tasks.length > 0) {
if (tasks[tasks.length - 1].start <= time) {
const task = tasks.pop();
queue.enqueue(task, task.time * 100000 + task.index);
} else {
break;
}
}
const { element: task } = queue.dequeue();
time += task.time;
answer.push(task.index);
}
return answer;
};
getOrder = function (tasks) {
const queue = new MinPriorityQueue()
tasks = tasks.map((task, index) => ({
index,
start: task[0],
time: task[1]
}))
tasks.sort((a, b) => b.start - a.start)
const answer = []
let time = 0
while (tasks.length > 0 || !queue.isEmpty()) {
if (queue.isEmpty() && tasks[tasks.length - 1].start > time) {
time = tasks[tasks.length - 1].start
}
while (tasks.length > 0) {
if (tasks[tasks.length -1].start <= time) {
const task = tasks.pop()
queue.enqueue(task, task.time * 100000 + task.index)
} else {
break
}
}
// 执行任务
const { element: task } = queue.dequeue()
time += task.time
answer.push(task.index)
}
return answer
}
class Solution:
def getOrder(self, tasks: List[List[int]]) -> List[int]:
n = len(tasks)
indices = list(range(n))
indices.sort(key=lambda x: tasks[x][0])
ans,q = [],[]
timestamp = 0
ptr = 0
for i in range(n):
if not q:
timestamp = max(timestamp, tasks[indices[ptr]][0])
while ptr < n and tasks[indices[ptr]][0] <= timestamp:
heapq.heappush(q, (tasks[indices[ptr]][1], indices[ptr]))
ptr += 1
process, index = heapq.heappop(q)
timestamp += process
ans.append(index)
return ans
1834. 单线程 CPU
入选理由
暂无
题目地址
https://leetcode-cn.com/problems/single-threaded-cpu/
前置知识
题目描述
现有一个单线程 CPU ,同一时间只能执行 最多一项 任务,该 CPU 将会按照下述方式运行:
如果 CPU 空闲,且任务队列中没有需要执行的任务,则 CPU 保持空闲状态。 如果 CPU 空闲,但任务队列中有需要执行的任务,则 CPU 将会选择 执行时间最短 的任务开始执行。如果多个任务具有同样的最短执行时间,则选择下标最小的任务开始执行。 一旦某项任务开始执行,CPU 在 执行完整个任务 前都不会停止。 CPU 可以在完成一项任务后,立即开始执行一项新任务。
返回 CPU 处理任务的顺序。
示例 1:
输入:tasks = [[1,2],[2,4],[3,2],[4,1]] 输出:[0,2,3,1] 解释:事件按下述流程运行:
示例 2:
输入:tasks = [[7,10],[7,12],[7,5],[7,4],[7,2]] 输出:[4,3,2,0,1] 解释:事件按下述流程运行:
提示:
tasks.length == n 1 <= n <= 105 1 <= enqueueTimei, processingTimei <= 109