leetcode
leetcode 2201 ~ 2250
完成所有任务的最少时间

完成所有任务的最少时间

难度:

标签:

题目描述

There is a computer that can run an unlimited number of tasks at the same time. You are given a 2D integer array tasks where tasks[i] = [starti, endi, durationi] indicates that the ith task should run for a total of durationi seconds (not necessarily continuous) within the inclusive time range [starti, endi].

You may turn on the computer only when it needs to run a task. You can also turn it off if it is idle.

Return the minimum time during which the computer should be turned on to complete all tasks.

 

Example 1:

Input: tasks = [[2,3,1],[4,5,1],[1,5,2]]
Output: 2
Explanation: 
- The first task can be run in the inclusive time range [2, 2].
- The second task can be run in the inclusive time range [5, 5].
- The third task can be run in the two inclusive time ranges [2, 2] and [5, 5].
The computer will be on for a total of 2 seconds.

Example 2:

Input: tasks = [[1,3,2],[2,5,3],[5,6,2]]
Output: 4
Explanation: 
- The first task can be run in the inclusive time range [2, 3].
- The second task can be run in the inclusive time ranges [2, 3] and [5, 5].
- The third task can be run in the two inclusive time range [5, 6].
The computer will be on for a total of 4 seconds.

 

Constraints:

  • 1 <= tasks.length <= 2000
  • tasks[i].length == 3
  • 1 <= starti, endi <= 2000
  • 1 <= durationi <= endi - starti + 1

代码结果

运行时间: 54 ms, 内存: 17.1 MB


/*
 * Problem Description: 
 * You have a computer that can run an infinite number of tasks simultaneously. Given a 2D integer array 'tasks' where tasks[i] = [start_i, end_i, duration_i] indicates that the i-th task needs to run for 'duration_i' integer time points within the closed interval [start_i, end_i]. You can turn the computer on when a task needs to run and turn it off when idle. Return the minimum number of seconds the computer needs to run to complete all tasks.
 * 
 * Approach: 
 * 1. Sort the tasks by their end time to ensure we can use the latest possible time points. 
 * 2. Use a priority queue to track the current running tasks and their end times. 
 * 3. Traverse through the tasks, updating the priority queue and calculating the required run times.
 */

import java.util.*;
import java.util.stream.*;

public class MinRunTimeStream {
    public int minRunTime(int[][] tasks) {
        Arrays.sort(tasks, Comparator.comparingInt(task -> task[1]));
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        int[] currentTime = {0};
        Arrays.stream(tasks).forEach(task -> {
            int start = task[0];
            int end = task[1];
            int duration = task[2];
            IntStream.range(0, duration).forEach(i -> {
                if (!pq.isEmpty() && pq.peek() < start) {
                    currentTime[0] = pq.poll();
                } else {
                    currentTime[0] = Math.max(currentTime[0], start);
                }
                pq.offer(currentTime[0]++);
            });
        });
        return pq.size();
    }

    public static void main(String[] args) {
        MinRunTimeStream mrt = new MinRunTimeStream();
        int[][] tasks = {{2, 3, 1}, {4, 5, 1}, {1, 5, 2}};
        System.out.println(mrt.minRunTime(tasks)); // Output: 2
    }
}

解释

方法:

此题解使用贪心算法和区间合并策略,首先按照任务的结束时间对所有任务进行排序,确保我们总是优先处理最早结束的任务。使用一个栈来维护不重叠的运行时间段,栈中的每个元素记录当前任务的开始和结束时间以及截止当前任务的总运行时间。对于每个任务,我们检查它与栈中现有运行时间段的重叠情况,并计算还需运行的时间。如果当前任务的需求时间未被满足,我们会利用最后一个任务的结束时间与当前任务的结束时间之间的空隙来填充。这种方法确保了在满足所有任务的前提下,电脑的运行时间尽可能少。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
在题解中提到使用二分查找来处理任务,这里的二分查找是如何实现的?具体是基于哪些条件进行查找的?
在题解中,二分查找是通过Python的`bisect_left`函数来实现的。这个函数用于在一个有序列表中查找插入点,使得插入后列表仍保持有序。在这个场景中,`bisect_left(stack, (start,))`是用来找到第一个起始时间不小于当前任务的起始时间的已处理任务。这是基于假设`stack`已经按照每个任务的结束时间有序排列。查找的条件是任务的起始时间,目的是为了确定当前任务可能受到哪些已经处理过的任务的影响(即找到可能与当前任务重叠的最后一个任务)。
🦆
请解释代码中`d -= stack[-1][2] - s`和`d -= r - start + 1 if start <= r else 0`这两行代码的具体作用和计算逻辑。
代码中`d -= stack[-1][2] - s`这行代码的作用是从当前任务需要的运行时间`d`中减去由于与前一个任务重叠而已经计算过的运行时间。这里`stack[-1][2]`表示栈顶元素(即最后处理的时间段)的累积运行时间,而`s`是与当前任务可能重叠的最后一个任务的累积运行时间。这样`stack[-1][2] - s`就给出了在当前任务的开始时间前已经累积的运行时间,需要从`d`中减去这部分重叠的运行时间。 `d -= r - start + 1 if start <= r else 0`这行代码的作用是处理当前任务与前一个任务的时间重叠的情况。如果当前任务的开始时间`start`小于或等于前一个任务的结束时间`r`,则当前任务的部分或全部时间可能已被前一个任务覆盖。`r - start + 1`计算的是从当前任务开始到前一个任务结束的时间段长度,这段时间不需要再次计算,因此从`d`中减去。如果`start`大于`r`,则没有重叠,不需要减去任何值。

相关问题