Welcome to Subscribe On Youtube

Formatted question description: https://leetcode.ca/all/1834.html

1834. Single-Threaded CPU

Level

Medium

Description

You are given n tasks labeled from 0 to n - 1 represented by a 2D integer array tasks, where tasks[i] = [enqueueTime_i, processingTime_i] means that the ith task will be available to process at enqueueTime_i and will take processingTime_i to finish processing.

You have a single-threaded CPU that can process at most one task at a time and will act in the following way:

  • If the CPU is idle and there are no available tasks to process, the CPU remains idle.
  • If the CPU is idle and there are available tasks, the CPU will choose the one with the shortest processing time. If multiple tasks have the same shortest processing time, it will choose the task with the smallest index.
  • Once a task is started, the CPU will process the entire task without stopping.
  • The CPU can finish a task then start a new one instantly.

Return the order in which the CPU will process the tasks.

Example 1:

Input: tasks = [[1,2],[2,4],[3,2],[4,1]]

Output: [0,2,3,1]

Explanation: The events go as follows:

  • At time = 1, task 0 is available to process. Available tasks = {0}.
  • Also at time = 1, the idle CPU starts processing task 0. Available tasks = {}.
  • At time = 2, task 1 is available to process. Available tasks = {1}.
  • At time = 3, task 2 is available to process. Available tasks = {1, 2}.
  • Also at time = 3, the CPU finishes task 0 and starts processing task 2 as it is the shortest. Available tasks = {1}.
  • At time = 4, task 3 is available to process. Available tasks = {1, 3}.
  • At time = 5, the CPU finishes task 2 and starts processing task 3 as it is the shortest. Available tasks = {1}.
  • At time = 6, the CPU finishes task 3 and starts processing task 1. Available tasks = {}.
  • At time = 10, the CPU finishes task 1 and becomes idle.

Example 2:

Input: tasks = [[7,10],[7,12],[7,5],[7,4],[7,2]]

Output: [4,3,2,0,1]

Explanation: The events go as follows:

  • At time = 7, all the tasks become available. Available tasks = {0,1,2,3,4}.
  • Also at time = 7, the idle CPU starts processing task 4. Available tasks = {0,1,2,3}.
  • At time = 9, the CPU finishes task 4 and starts processing task 3. Available tasks = {0,1,2}.
  • At time = 13, the CPU finishes task 3 and starts processing task 2. Available tasks = {0,1}.
  • At time = 18, the CPU finishes task 2 and starts processing task 0. Available tasks = {1}.
  • At time = 28, the CPU finishes task 0 and starts processing task 1. Available tasks = {}.
  • At time = 40, the CPU finishes task 1 and becomes idle.

Constraints:

  • tasks.length == n
  • 1 <= n <= 10^5
  • 1 <= enqueueTimei, processingTimei <= 10^9

Solution

For each task, store its index as well. Then sort the tasks according to the enqueue times. Use a priority queue to store the tasks, where the task with the shortest processing time and the smallest index in case of a tie is polled first.

Loop over the sorted tasks. For each task, if the task’s enqueue time is before or the same as the current time, or the priority queue is empty, offer it to the priority queue. Otherwise, poll a task from the priority queue, put the task’s index to the result array, and update the current time accordingly.

After the tasks are looped over, while the priority queue is not empty, poll the tasks from the priority queue, put the task’s index to the result array, and update the current time accordingly.

Finally, return the result array.

  • class Solution {
        public int[] getOrder(int[][] tasks) {
            int n = tasks.length;
            long[][] newTasks = new long[n][3];
            for (int i = 0; i < n; i++) {
                newTasks[i][0] = (long) tasks[i][0];
                newTasks[i][1] = (long) tasks[i][1];
                newTasks[i][2] = (long) i;
            }
            Arrays.sort(newTasks, new Comparator<long[]>() {
                public int compare(long[] task1, long[] task2) {
                    if (task1[0] == task2[0])
                        return 0;
                    else if (task1[0] > task2[0])
                        return 1;
                    else
                        return -1;
                }
            });
            int[] order = new int[n];
            PriorityQueue<long[]> priorityQueue = new PriorityQueue<long[]>(new Comparator<long[]>() {
                public int compare(long[] task1, long[] task2) {
                    if (task1[1] != task2[1])
                        return task1[1] > task2[1] ? 1 : -1;
                    else
                        return task1[2] > task2[2] ? 1 : -1;
                }
            });
            int index = 0, orderIndex = 0;
            long curTime = newTasks[index][0];
            while (index < n) {
                long[] task = newTasks[index];
                if (task[0] <= curTime || priorityQueue.isEmpty()) {
                    priorityQueue.offer(task);
                    curTime = Math.max(curTime, task[0]);
                    index++;
                } else {
                    long[] nextTask = priorityQueue.poll();
                    order[orderIndex++] = (int) nextTask[2];
                    curTime = Math.max(curTime + nextTask[1], nextTask[0] + nextTask[1]);
                }
            }
            while (!priorityQueue.isEmpty()) {
                long[] nextTask = priorityQueue.poll();
                order[orderIndex++] = (int) nextTask[2];
                curTime = Math.max(curTime + nextTask[1], nextTask[0] + nextTask[1]);
            }
            return order;
        }
    }
    
    ############
    
    class Solution {
        public int[] getOrder(int[][] tasks) {
            int n = tasks.length;
            int[][] ts = new int[n][3];
            for (int i = 0; i < n; ++i) {
                ts[i] = new int[] {tasks[i][0], tasks[i][1], i};
            }
            Arrays.sort(ts, (a, b) -> a[0] - b[0]);
            int[] ans = new int[n];
            PriorityQueue<int[]> q
                = new PriorityQueue<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
            int i = 0, t = 0, k = 0;
            while (!q.isEmpty() || i < n) {
                if (q.isEmpty()) {
                    t = Math.max(t, ts[i][0]);
                }
                while (i < n && ts[i][0] <= t) {
                    q.offer(new int[] {ts[i][1], ts[i][2]});
                    ++i;
                }
                var p = q.poll();
                ans[k++] = p[1];
                t += p[0];
            }
            return ans;
        }
    }
    
  • class Solution:
        def getOrder(self, tasks: List[List[int]]) -> List[int]:
            for i, task in enumerate(tasks):
                task.append(i)
            tasks.sort()
            ans = []
            q = []
            n = len(tasks)
            i = t = 0
            while q or i < n:
                if not q:
                    t = max(t, tasks[i][0])
                while i < n and tasks[i][0] <= t:
                    heappush(q, (tasks[i][1], tasks[i][2]))
                    i += 1
                pt, j = heappop(q)
                ans.append(j)
                t += pt
            return ans
    
    ############
    
    # 1834. Single-Threaded CPU
    # https://leetcode.com/problems/single-threaded-cpu/
    
    class Solution:
        def getOrder(self, tasks: List[List[int]]) -> List[int]:
            n = len(tasks)
            available = collections.defaultdict(list)
            t = float('inf')
            
            for i, (a,b) in enumerate(tasks):
                available[a].append((b, i))
                t = min(t, a)
            
            res = []
            heap = []
            ki = 0
            kn = len(available)
            keys = list(available.keys())
            keys.sort()
    
            while len(res) != n:
                isUpdated = False
                while ki < kn and keys[ki] <= t:
                    new = available[keys[ki]]
                    for at in new:
                        heap.append(at)
                    isUpdated = True
                    ki += 1
                
                if isUpdated:
                    heapq.heapify(heap)
                
                if ki == kn:
                    while heap:
                        time, i = heapq.heappop(heap)
                        res.append(i)
                else:
                    if heap:
                        time, i = heapq.heappop(heap)
                        t += time
                        res.append(i)
                    else:
                        t = keys[ki]
            
            return res
    
    
  • class Solution {
    public:
        vector<int> getOrder(vector<vector<int>>& tasks) {
            int n = 0;
            for (auto& task : tasks) task.push_back(n++);
            sort(tasks.begin(), tasks.end());
            using pii = pair<int, int>;
            priority_queue<pii, vector<pii>, greater<pii>> q;
            int i = 0;
            long long t = 0;
            vector<int> ans;
            while (!q.empty() || i < n) {
                if (q.empty()) t = max(t, (long long) tasks[i][0]);
                while (i < n && tasks[i][0] <= t) {
                    q.push({tasks[i][1], tasks[i][2]});
                    ++i;
                }
                auto [pt, j] = q.top();
                q.pop();
                ans.push_back(j);
                t += pt;
            }
            return ans;
        }
    };
    
  • func getOrder(tasks [][]int) (ans []int) {
    	for i := range tasks {
    		tasks[i] = append(tasks[i], i)
    	}
    	sort.Slice(tasks, func(i, j int) bool { return tasks[i][0] < tasks[j][0] })
    	q := hp{}
    	i, t, n := 0, 0, len(tasks)
    	for len(q) > 0 || i < n {
    		if len(q) == 0 {
    			t = max(t, tasks[i][0])
    		}
    		for i < n && tasks[i][0] <= t {
    			heap.Push(&q, pair{tasks[i][1], tasks[i][2]})
    			i++
    		}
    		p := heap.Pop(&q).(pair)
    		ans = append(ans, p.i)
    		t += p.t
    	}
    	return
    }
    
    func max(a, b int) int {
    	if a > b {
    		return a
    	}
    	return b
    }
    
    type pair struct{ t, i int }
    type hp []pair
    
    func (h hp) Len() int            { return len(h) }
    func (h hp) Less(i, j int) bool  { return h[i].t < h[j].t || (h[i].t == h[j].t && h[i].i < h[j].i) }
    func (h hp) Swap(i, j int)       { h[i], h[j] = h[j], h[i] }
    func (h *hp) Push(v interface{}) { *h = append(*h, v.(pair)) }
    func (h *hp) Pop() interface{}   { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
    

All Problems

All Solutions