小M的多任务下载器挑战
问题描述
小M的程序设计大作业是编写一个多任务下载器。在实现过程中,他遇到了一个问题:在一次下载过程中,总共有N个任务,每个任务会在第x秒开始,并持续y秒。小M需要知道,在同一时刻,最多有多少个任务正在同时下载,也就是计算出任务的最高并发数。
解题思路:
我们首先将问题建模,把时间看成一个坐标轴,一个任务就相当于一条覆盖的直线,在代码中,就可以用一个数组表示,数组初始元素全为0,加入一个任务就是把对应的元素加1,然后遍历数组,统计哪个下标的值最大即可,这样做的话需要两重循环,外层循环遍历所有的任务,内层循环遍历任务影响坐标,复杂度是,对于数据范围较大的情况就不适用了。我们考虑使用差分数组降低复杂度,差分数组形式化地讲就是对于一个数组a,我们新建一个数组b,其中。将差分数组用于这道题目,对于单个任务i,任务的持续时间为,那么我们可以将差分数组的下标的值加1,下标的值减一,最后只需要遍历一遍差分数组,每次加上当前数组元素,与答案取最大值即可。由于题目没有给出具体的数据范围,为了防止超出数组最大可分配空间,需要使用离散化对坐标进行映射处理。(不用离散化能不能通过我没有进行实验...)离散化的思路是将坐标从小到大进行排序并去重,然后原来的坐标一一对应现在所处的位置,例如,离散化后的原数组对应的新值是,这样就不用担心出现1e9这样的大坐标导致数组无法开这么大。具体实现可以参考下面的代码。
代码:
import java.util.*;
public class Main {
public static int solution(int n, int[][] array) {
// Edit your code here
TreeSet<Integer> set = new TreeSet<>();
for (int i = 0; i < n; ++i) {
set.add(array[i][0]);
set.add(array[i][0] + array[i][1]);
}
Map<Integer, Integer> map = new HashMap<>();
int cnt = 0;
for (int i : set)
map.put(i, ++cnt);
int[] a = new int[cnt + 10];
for (int i = 0; i < n; ++i) {
a[map.get(array[i][0])]++;
a[map.get(array[i][0] + array[i][1])]--;
}
int now = 0, ans = 0;
for (int i = 1; i <= cnt; ++i) {
now += a[i];
ans = Math.max(ans, now);
}
return ans;
}
public static void main(String[] args) {
// Add your test cases here
System.out.println(solution(2, new int[][]{{1, 2}, {2, 3}}) == 2);
System.out.println(solution(4, new int[][]{{1, 2}, {2, 3}, {3, 5}, {4, 3}}) == 3);
}
}
代码解析:
使用TreeSet和HashMap进行离散化操作,由于TreeSet中存储的元素是有序且唯一的,所以可以很方便地进行离散化操作,将所有坐标放入TreeSet后,直接从小到大遍历并把坐标对应离散化后的新值记录到HashMap中,最后在差分数组上进行遍历并更新答案,注意在离散化后坐标都要使用map.get()方法得到对应的新值。