leetcode-pp / 91alg-8-daily-check

5 stars 0 forks source link

【Day 33 】2022-08-16 - 1834. 单线程 CPU #48

Closed azl397985856 closed 1 year ago

azl397985856 commented 2 years ago

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

laofuWF commented 2 years 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
XingZhaoDev commented 2 years ago
 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;
    }
lsunxh commented 2 years ago

Priority Queue

Time: O(NlogN), space: O(N)

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
flaming-cl commented 2 years ago
// 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;
    }
}
mannnn6 commented 2 years ago
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
SunnyYuJF commented 2 years ago

思路

Priority Queue

代码 Python

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)

MichaelXi3 commented 2 years ago

Idea

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

}

aiweng1981 commented 2 years ago

思路

  • 思路描述:先开始不明白,仔细看就清楚了

代码

#代码
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)
tobepellucid commented 2 years ago
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
wzasd commented 2 years ago
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;
    }
}
testplm commented 2 years ago
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
shiyishuoshuo commented 2 years ago

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;
    }
}
cytrue commented 2 years ago

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

2learnsomething commented 2 years ago
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
caterpillar-0 commented 2 years ago

思路

两个优先队列,分别对开始时间和执行时间进行排序

代码

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

复杂度分析

ceramickitten commented 2 years ago

思路

两个队列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

Tlntin commented 2 years ago

题目链接

-链接

代码

#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;
}

复杂度:

结果

4d094b89aa8ffece550586fe0c953d55.png

dereklisdr commented 2 years ago

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

}

LiquanLuo commented 2 years ago
/***
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;

    }
};
thinkfurther commented 2 years ago
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)

ILoveQier commented 2 years ago
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;
};
Whisht commented 2 years ago
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
xixiao51 commented 2 years ago

Idea

Heap

Code

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

xy147 commented 2 years ago

思路

排序+优先队列

js代码

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
}

复杂度分析

zch-bit commented 2 years ago

Day 33

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
}
xxiaomm commented 2 years ago
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;
    }

}
UCASHurui commented 2 years ago

思路


使用两个数据结构,一个数组保存节点下标,并且根据入队列时间排序,另外使用一个小顶堆,保存当前队列中的任务,每次弹出堆定的元素进行执行,按照上述思路进行模拟。

代码


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

复杂度分析


AtaraxyAdong commented 2 years ago

思路

通过题解学习

按照题目情况进行模拟,需要使用新的数组记录任务的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;
    }
}

复杂度分析

joeymoso commented 2 years ago
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
haoyangxie commented 2 years ago

code

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

complexity

Time: O(nlgn) Space: O(n)

ashleyyma6 commented 2 years ago

Idea

Code

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

nikojxie commented 2 years ago

代码

/**
 * @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;
}
mo-xiaoxiu commented 2 years ago

思路

具体实现

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;
    }
};
phoenixflyingsky commented 2 years ago

//最近太忙了,后面看看

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

Xinyi-arch commented 2 years ago

思路

优先队列

Code

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
uyplayer commented 2 years ago

LC 1834. 单线程 CPU

题目大意

给你一个二维数组 tasks ,用于表示项从 0 到 n - 1 编号的任务。其中 tasks[i] = [enqueueTimei, processingTimei] 意味着第 i 项任务将会于 enqueueTimei 时进入任务队列,需要 processingTimei 的时长完成执行。

现有一个单线程 CPU ,同一时间只能执行 最多一项 任务,该 CPU 将会按照下述方式运行:

如果 CPU 空闲,且任务队列中没有需要执行的任务,则 CPU 保持空闲状态。 如果 CPU 空闲,但任务队列中有需要执行的任务,则 CPU 将会选择 执行时间最短 的任务开始执行。如果多个任务具有同样的最短执行时间,则选择下标最小的任务开始执行。 一旦某项任务开始执行,CPU 在 执行完整个任务 前都不会停止。 CPU 可以在完成一项任务后,立即开始执行一项新任务。 返回 CPU 处理任务的顺序。

思路


思路1

给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
}

复杂度分析

richypang commented 2 years ago

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
findalyzhou commented 2 years ago

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

eden-ye commented 2 years ago

思路

模拟,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;
    }
}

复杂度

Cusanity commented 2 years ago

Solution

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;
    }
}
tian-pengfei commented 2 years ago
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;

    }
};
zzz607 commented 2 years ago

思路

  1. 总体上,每执行完成一个任务,就当将前时间向前推进完成该任务所消耗的时间,这样就得到当前最新的时间。
  2. 然后从队列中取出所有小于当前时间的所有任务,并加入到最小堆中,按照消耗时间、下标进行排序
  3. 重复以上二个步骤,直到所有的任务完成

有一个特殊的情况,任务队列中所有任务的时入时间均小于第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
}

复杂度

  1. 空间复杂度:O(n)
  2. 时间复杂度:第一个循环花费O(n),排序花费O(nlogn),第二个循环和后面那个三重循环需要整体考虑:这二个操作将tasks数组进入堆一次,出堆一次,并且没有重复遍历tasks,因此,这个时间复杂度也是O(nlogn),所以,总的时间花费是:O(n+2nlogn) = O(nlogn)
LuckyRyan-web commented 2 years ago

// 先熟悉一下堆,后面再来做这道题

/**
 * @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;
};
Elon-Lau commented 2 years ago

思路

  • 思路描述

代码

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

复杂度

  • 时间复杂度:
  • 空间复杂度:
guixian001 commented 2 years ago

思路: 一个数组存储(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
passengersa commented 2 years ago

解题思路

设计一个优先队列(堆),将任务按起始时间排序后,根据当前时间线依次入队,再从队列中根据题目要求取出优先级最高的任务执行,直至完成全部任务。

代码

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;
    }
}
zzzkaiNS commented 2 years ago

打卡

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;
    }
};
Jiangwenzhe commented 2 years ago
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;
};
zpc7 commented 2 years ago
 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
}
hyqqq22 commented 2 years ago
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