题目
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 行。
其中每一行的格式是:
ts id
表示在 时刻编号 的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 的时间段内收到不少于 个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻 满足该帖在 这段时间内(注意是左闭右开区间)收到不少于 个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
输入格式
第一行包含三个整数 。
以下 行每行一条日志,包含两个整数 和 。
输出格式
按从小到大的顺序输出热帖 。
每个 占一行。
数据范围
,
,
输入样例:
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
输出样例:
1
3
解题
方法一:双指针 滑动窗口
思路
与【双指针】字符串删减类似都是利用双指针思想,维护一个定长的滑动窗口,然后更新窗口内的计数。不过本题的实现稍微麻烦一点,首先要把输入的日子以时间 ts
为下标把 id
存入数组中(注意同一时间可能有多个 id
所以数组里还得套一层列表),然后维护一个长度为 的滑动窗口,在每次有新的 id
加入窗口时检查该 id
在当前窗口内获点赞的数量,如果大于 k
就放入结果集合(使用树集既去重又排序),最后按顺序输出结果集合即可。
代码
import java.util.*;
import java.io.*;
public class Main {
static final int N = (int) 1e5 + 10;
public static void main(String[] args) throws IOException {
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
int n = (int) in.nval;
in.nextToken();
int d = (int) in.nval;
in.nextToken();
int k = (int) in.nval;
List<Integer>[] logs = new ArrayList[N];
int sz = 0;
while (n-- > 0) {
in.nextToken();
int ts = (int) in.nval;
in.nextToken();
int id = (int) in.nval;
if (logs[ts] == null) logs[ts] = new ArrayList<>();
logs[ts].add(id);
sz = Math.max(sz, ts + 1);
}
int[] cnts = new int[N];
Set<Integer> ans = new TreeSet<>();
for (int l = 0, r = 0; r < sz; ++r) {
if (logs[r] != null) {
for (int id : logs[r]) {
if (++cnts[id] >= k) ans.add(id);
}
}
if (r - l + 1 >= d) {
if (logs[l] != null) {
for (int id : logs[l]) --cnts[id];
}
++l;
}
}
for (int id : ans) System.out.println(id);
}
}
评论区