日志统计
- 1.题目
- 2.基本思想
- 3.代码实现
1.题目
小明维护着一个程序员论坛。现在他收集了一份”点赞”日志,日志共有 N N N 行。
其中每一行的格式是:
ts id
表示在 t s ts ts 时刻编号 i d id id 的帖子收到一个”赞”。
现在小明想统计有哪些帖子曾经是”热帖”。
如果一个帖子曾在任意一个长度为 D D D 的时间段内收到不少于 K K K 个赞,小明就认为这个帖子曾是”热帖”。
具体来说,如果存在某个时刻
T
T
T满足该帖在
[
T
,
T
+
D
)
[T,T+D)
[T,T+D)这段时间内(注意是左闭右开区间)收到不少于
K
K
K
个赞,该帖就曾是”热帖”。
给定日志,请你帮助小明统计出所有曾是”热帖”的帖子编号。
输入格式
第一行包含三个整数
N
,
D
,
K
N,D,K
N,D,K。
以下
N
N
N 行每行一条日志,包含两个整数
t
s
ts
ts和
i
d
id
id。
输出格式
按从小到大的顺序输出热帖
i
d
id
id。
每个 i d id id 占一行。
数据范围
1
≤
K
≤
N
≤
105
1≤K≤N≤105
1≤K≤N≤105,
0
≤
t
s
,
i
d
≤
105
0≤ts,id≤105
0≤ts,id≤105,
1
≤
D
≤
10000
1≤D≤10000
1≤D≤10000
输入样例:
7 10 2
0 1
0 10
10 10
10 1
9 1
100 3
100 3
输出样例:
1
3
2.基本思想
暴力做法:如果用暴力的话我们应该枚举两重循环,一重枚举时间,一重枚举id
暴力伪代码
for (时间段) {
for (id) {
cnt[id]++;
//判断区间是否满足D
if (cnt[id] >= k) st[id] = ture; // 如果是热帖 标记为true
}
}
- 由于枚举区间时,会有很大一部分重复,假设我们已经统计了上面区间的id次数,那我统计下面区间id次数,我们可以直接把开头去掉,把结尾加上即可:
cnt[id[j]]--
,cnt[id[i]]++
基本思想:
排序
+双指针
① 先将所有的点赞👍数量按照时间🕛顺序排好
② 通过双指针i和j维护长度不大于d的区间,并记录该区间的中所有帖子获得的赞数
for (时间段) {
cnt[id[j]]--; // 减去开头
cnt[id[i]]++; // 加上结尾
}
3.代码实现
import java.util.Arrays;
import java.util.Scanner;
public class _1238日志统计 {
static class PII implements Comparable<PII> {
int ts, id;
public PII(int ts, int id) {
this.ts = ts;
this.id = id;
}
@Override
public int compareTo(PII o) {
if (this.ts > o.ts) return 1;
if (this.ts == o.ts) {
if (this.id > o.id) return 1;
else return -1;
}
return -1;
}
}
static Scanner sc = new Scanner(System.in);
static PII logs[] = new PII[100010];//保存 记录
static int cnt[] = new int[100010];//用来记录一个id号获得的赞数,表示形式为cnt[id]++;
static boolean st[] = new boolean[100010];//用来标记id号,因为id <= 1e5,所以可以利用遍历来输出。
public static void main(String[] args) {
int N = sc.nextInt(), D = sc.nextInt(), K = sc.nextInt();//N行数据 时间长度为D 不少于K个赞
for (int i = 0; i < N; i++)
logs[i] = new PII(sc.nextInt(), sc.nextInt());
Arrays.sort(logs, 0, N);//按时间 排序处理
//双指针算法 i走的块 j在后面跟着
for (int i = 0, j = 0; i < N; i++) {
int i_id = logs[i].id;//表示i时刻的id号
cnt[i_id]++;
while (logs[i].ts - logs[j].ts >= D) {//两指针跨越时间超过D 去除早期 赞的记录
cnt[logs[j].id]--;
j++;//后移遍历
}
if (cnt[i_id] >= K) st[i_id] = true;//记录i_id 是否为 热赞
}
for (int i = 0; i < 100010; i++)
if (st[i]) System.out.println(i);
}
}