目标
给你一个整数 n ,表示服务器的总数目,再给你一个下标从 0 开始的 二维 整数数组 logs ,其中 logs[i] = [server_id, time] 表示 id 为 server_id 的服务器在 time 时收到了一个请求。
同时给你一个整数 x 和一个下标从 0 开始的整数数组 queries 。
请你返回一个长度等于 queries.length 的数组 arr ,其中 arr[i] 表示在时间区间 [queries[i] - x, queries[i]] 内没有收到请求的服务器数目。
注意时间区间是个闭区间。
示例 1:
输入:n = 3, logs = [[1,3],[2,6],[1,5]], x = 5, queries = [10,11]
输出:[1,2]
解释:
对于 queries[0]:id 为 1 和 2 的服务器在区间 [5, 10] 内收到了请求,所以只有服务器 3 没有收到请求。
对于 queries[1]:id 为 2 的服务器在区间 [6,11] 内收到了请求,所以 id 为 1 和 3 的服务器在这个时间段内没有收到请求。
示例 2:
输入:n = 3, logs = [[2,4],[2,1],[1,2],[3,1]], x = 2, queries = [3,4]
输出:[0,1]
解释:
对于 queries[0]:区间 [1, 3] 内所有服务器都收到了请求。
对于 queries[1]:只有 id 为 3 的服务器在区间 [2,4] 内没有收到请求。
提示:
- 1 <= n <= 10^5
- 1 <= logs.length <= 10^5
- 1 <= queries.length <= 10^5
- logs[i].length == 2
- 1 <= logs[i][0] <= n
- 1 <= logs[i][1] <= 10^6
- 1 <= x <= 10^5
- x < queries[i] <= 10^6
思路
有 n 台服务器编号为 1 ~ n,有一个二维数组 logs,logs[i] = [id, time] 表示在 time 时刻编号为 id 的服务器收到了请求。另外有一个查询数组 queries,针对每个查询,返回在时间 [queries[i] - x, queries[i]] 内没有接收到请求的服务器数目。
将 logs 按照时间排序,针对每一个查询,在 logs 上滑动窗口,同时维护窗口内的服务器请求数 cnt 数组,以及未收到请求的服务器数,初始化 noMessageServer = n。滑动窗口,如果时间小于等于 queries[i] 对于第一次出现的服务器 id,noMessageServer--,然后计数 cnt[id]++。收缩左边界,如果时间小于 queries[i] - x,cnt[id]--,如果 cnt[id] == 0,noMessageServer++。
代码
/**
* @date 2026-11-06 10:24
*/
public class CountServers2747 {
public int[] countServers_v1(int n, int[][] logs, int x, int[] queries) {
Arrays.sort(logs, (a, b) -> a[1] - b[1]);
int ql = queries.length;
int[] res = new int[ql];
int[][] qs = new int[ql][2];
for (int i = 0; i < ql; i++) {
qs[i] = new int[]{i, queries[i]};
}
Arrays.sort(qs, (a, b) -> a[1] - b[1]);
int l = 0, r = 0, m = logs.length;
int[] cnt = new int[n + 1];
int noMessageServer = n;
for (int[] q : qs) {
while (r < m && logs[r][1] <= q[1]) {
int id = logs[r++][0];
if (cnt[id] == 0) {
noMessageServer--;
}
cnt[id]++;
}
while (l < m && logs[l][1] < q[1] - x) {
int id = logs[l++][0];
cnt[id]--;
if (cnt[id] == 0) {
noMessageServer++;
}
}
res[q[0]] = noMessageServer;
}
return res;
}
}
性能
